最完美的单例模式

Posted 再等三分钟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最完美的单例模式相关的知识,希望对你有一定的参考价值。

在工作中用最常用的选择是饿汉式和双重检查懒汉式。最完美的是Effective Java中推荐的enum方式

1、恶汉式:
      类加载到内存中,就实例化一个单例,JVM保证线程安全,简单实用
      一个小缺点:无论用到与否,类加载时就完成实例化

public class HungrySingleton {
    private static final HungrySingleton INSTANCE = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return INSTANCE;
    }

2、懒汉式

一个是在静态方法上加锁,相当于锁定了整个类,可能会对效率有影响

public class LazySingleton1 {

    private static  LazySingleton1 INSTANCE;

    private LazySingleton1() {
    }

    /**
     * 1、静态方法加锁,锁定了LazySingleton
     *
     * @return
     */
    public static synchronized LazySingleton1 getInstance1() {
        if (INSTANCE == null) {
            INSTANCE = new LazySingleton1();
        }
        return INSTANCE;
    }

双重检查机制:要加volatile,防止JVM的指令重排

public class LazySingleton2 {

    private static volatile LazySingleton2 INSTANCE;
    /**
     * 2、此方法不行,
     * 当一个线程A执行到if时,暂停,另一个线程B进来,判断为空,则new,A接着执行会再次创建,所以出现了二次加锁
     *
     * @return
     */
    public static synchronized LazySingleton2 getInstance1() {
        if (INSTANCE == null) {
            synchronized (LazySingleton2.class) {
                INSTANCE = new LazySingleton2();
            }
        }
        return INSTANCE;
    }

    /**
     * 3、双重检查
     * 要加volatile,防止JVM的指令重排
     *
     * @return
     */
    public static synchronized LazySingleton2 getInstance() {
        if (INSTANCE == null) {
            synchronized (LazySingleton2.class) {
                if (INSTANCE == null) {
                    INSTANCE = new LazySingleton2();
                }
            }
        }
        return INSTANCE;
    }

}

3、通过静态内部类实现: 在LazySingleton加载时,内部静态类LazyHolder是不会被加载的,在getInstance时才会new,相当于实现了懒加载。线程安全是由JVM保证的,JVM在加载时,一个类只会加载一次,所以不会出现并发问题。

public class LazySingleton3 {

    private static class LazyHolder {
        private final static LazySingleton3 LAZY_SINGLETON = new LazySingleton3();
    }

    public static LazySingleton3 getInstance4() {
        return LazyHolder.LAZY_SINGLETON;
    }

4、通过枚举实现单例:

    枚举单例:Effective Java中推荐这么写, 不仅可以解决线程同步,还可以防止反序列化(枚举类没有构造方法)  


public enum PerfectLazySingleton {

    INTANCE;

}

在工作中基本饿汉式就可以了,有些人可能为了炫技,证明我懂锁,所以使用双重锁,也可以使用枚举单例,这种会对不知道的人有些奇怪。

以上是关于最完美的单例模式的主要内容,如果未能解决你的问题,请参考以下文章

最完美的单例模式

最完美的单例模式

在java中写出完美的单例模式

在java中写出完美的单例模式

在java中写出完美的单例模式

如何创建一个完美的单例模式