单例模式

2020-04-03  本文已影响0人  执着的逗比

1)通过静态常量实现的饿汉单例模式,类一加载即初始化,没有并发问题,但是如果类初始化过大,甚至后期没有使用,会造成资源浪费。

public class HungrySingleton {

    private final static HungrySingleton INSTANCE = new HungrySingleton();

    /*私有构造方法,防止被实例化*/
    private HungrySingleton() {}

    public HungrySingleton getInstance(){
        return INSTANCE;
    }

    public Object readResolve(){
        return INSTANCE;
    }

}

2)通过静态代码块实现的饿汉式单例,跟第一种一样的问题,类一加载即初始化,没有并发问题,但是如果类初始化过大,甚至后期没有使用,会造成资源浪费。

public class HungrySingleton {

    private static HungrySingleton instance;
    
    static{
        instance = new HungrySingleton();
    }

    /*私有构造方法,防止被实例化*/
    private HungrySingleton() {}

    public HungrySingleton getInstance(){
        return INSTANCE;
    }

    public Object readResolve(){
        return INSTANCE;
    }

}

3)一般的懒汉式单例模式,毫无线程安全保护,如果我们把他放入多线程的环境下,肯定会出现线程安全问题。

public class LazySingleton {

    private static LazySingleton instance = null;

    private LazySingleton() {
    }

    public static  LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }

    public Object readResolve() {
        return instance;
    }
}

4)通过synchronzied修饰方法的懒汉式单例模式,synchronzied关键字会把对象锁住,每次调用getInstance()时,都要把对象锁住,性能会有所下降。

public class LazySingleton {

    private static LazySingleton instance = null;

    private LazySingleton() {
    }

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }

    public Object readResolve() {
        return instance;
    }
}

5)通过synchronzied修饰代码块的懒汉式单例模式,这种方式,本意是想对第四种实现方式的改进,因为前面同步方法效率太低,改为同步产生实例化的的代码块,但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一致,假如一个线程进入了if (instance== null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。

public class LazySingleton {

    private static LazySingleton instance = null;

    private LazySingleton() {
    }

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
             synchronized (LazySingleton.class) {
                   instance = new LazySingleton();
                }
        }
        return instance;
    }

    public Object readResolve() {
        return instance;
    }
}

6)双重检查的单例模式,Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (instance == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象,也避免的反复进行方法同步,这种做法既可以保证线程安全,又可以延迟加载,效率较高。

public class LazyDoubleCheckSingleton {

    public static LazyDoubleCheckSingleton instance = null;

    public LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance() {
        if (instance == null) {
            synchronized (instance) {
                if (instance == null) {
                    instance = new LazyDoubleCheckSingleton();
                }
            }
        }
        return instance;
    }

    public Object readResolve() {
        return instance;
    }
}

7)通过静态内部类实现的单例模式,当LazyInnerSingleton第一次被加载的时,并不会去加载SingletonInstance,只有当getInstance()方法第一次调用的时候,才会去初始化INSTANCE,第一次调用调用getInstance()方法会使虚拟机去加载SingletonInstance类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

public class LazyInnerSingleton {
    public static LazyInnerSingleton instance = null;

    public LazyInnerSingleton() {
    }

    // 定义一个内部类,用来获得实例
    private static class SingletonInstance {
        private static final LazyInnerSingleton INSTANCE = new LazyInnerSingleton();

    }

    public static LazyInnerSingleton getInstance(){
        return SingletonInstance.INSTANCE;
    }

    public Object readResolve() {
        return instance;
    }
}

8)通过枚举实现的单例模式,这借助JDK1.5中添加的枚举来实现单例模式,枚举类型是线程安全的,并且只会装载一次,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

package singleton.enums;

public class Singleton {
    private String name;
    private String desc;
}
package singleton.enums;

public enum SingletonEnum {
    INSTANCE;

    private Singleton instance = null;

    private SingletonEnum(){
        instance = new Singleton();
    }

    public Singleton getInstance(){
        return instance;
    }
}

上一篇下一篇

猜你喜欢

热点阅读