java

设计模式--单例模式

2020-02-19  本文已影响0人  是哪的鸭

单例模式

一个类只能有一个对象。该类自己负责创建对象,同时确保只有一个对象被创建。

  1. 单例类只能有一个实例
  2. 单例类必须自己创建自己的唯一实例
  3. 单例类必须给其他所有类提供这一实例

使用场景:

实现方法

1.懒汉式

Lazy初始化:
线程安全:
描述: 最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

具体实现

//懒汉式线程安全做法为加锁,在getInstance方法上加sychronized锁。但是这样会影响效率
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
     //doSomething() 该实例支持的行为
}

2.饿汉式

Lazy初始化:
线程安全:
描述: 常用方法,但是容易产生垃圾对象。基于classloader机制避免了多线程的同步问题。在类加载时就实例化对象,没达到lazy loading效果

具体实现

public class Singleton{
    private static Singleton instance=new Singleton();
    private Singleton(){};
    public static Singleton getInstance(){
        return instance;
    }
     //doSomething() 该实例支持的行为
}

3.双检锁/双重校验锁(DCL)

JDK版本: 1.5起
Lazy初始化:
多线程安全:
描述: 采用双锁机制,安全且在多线程情况下能保持高性能。getInstance()的性能对程序很关键。

具体实现

public class Singleton{
    //当singleton不为null时通知想要实例化的其他线程  
    private volatile static Singleton singleton;
    private Singleton(){};
    public Singleton getInstance(){
        //判断是否为空,为空则获得sychronized锁
        if(instance==null){
            sychronized(Singleton.class);
            //获得sychronized锁后再次判断,防止获得锁时,已经被实例化。
            if(singleton==null){
                singleton=new Singleton();
            }
        }
        return singleton;
    }
    
     //doSomething() 该实例支持的行为
}

登记式/静态内部类

Lazy初始化:
线程安全:
描述: 能达到双检锁一样的功效。但是实现更简单。本方法采用classloader机制来确保初始化时只有一个线程。同饿汉式不同,饿汉式只要类被加载了,instance一定被实例化。本方法只有通过主动调用getInstance()来显示装在SingletonHolder,从而实例化instance

具体实现

    public class Singleton{
        private static class SingletonHolder{
            private static final Singleton INSTANCE =new Singleton();
        }
        private Singleton(){};
        public static final Singleton getInstance(){
            return SingletonHolder.INSTANCE;
        }
        
         //doSomething() 该实例支持的行为
    }

6.枚举

JDK版本: 1.5起
是否Lazy初始化:
多线程安全:
描述: 实现单例模式的最佳方法。简洁,而且支持序列化机制,绝对防止多次被实例化。代码可读性差

具体实现

    public enum Singleton{
        INSTANCE
        
        //doSomething() 该实例支持的行为
        
        //可以省略此方法,通过Single.INSTANCE进行操作
        public static Singleton getInstance(){
            return Singleton.INSTANCE
        }
        
    }

总结

枚举式不常用,可读性差。
既要求线程安全,又要求Lazy加载使用双检锁式。
要求线程安全,不要求Lazy加载使用饿汉式。

注意: 前五种方法可能会多次实例化,当实例被写入到文件到反序列化成实例时,会重复实例化。为了避免这种情况。如果涉及到序列化、反序列化时,我们需要重写readResolve方法,以让实例唯一。

private Object readResolve() throws ObjectStreamException{
    return singleton;
}
上一篇下一篇

猜你喜欢

热点阅读