单例模式的9种写法

1.饿汉式(静态常量) 推荐指数:★★☆☆☆

优点:不会有线程安全问题。
缺点:在类加载的时候就创建对象,如果一直没使用到该对象的话,就造成了内存浪费,如果对象初始化的工作很多也会影响性能。

public class Singleton1 {

    private final static Singleton1 INSTANCE = new Singleton1();

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        return INSTANCE;
    }
}

2.饿汉式(静态代码块) 推荐指数:★★☆☆☆

优缺点和第一种方式基本一致。

public class Singleton2 {

    private final static Singleton2 INSTANCE;

    static {
        INSTANCE = new Singleton2();
    }

    private Singleton2() {
    }

    public static Singleton2 getInstance() {
        return INSTANCE;
    }
}

3.懒汉式(线程不安全) 推荐指数:★☆☆☆☆

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。
缺点:有线程安全问题。

public class Singleton3 {

    private static Singleton3 instance;

    private Singleton3() {

    }

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

4.懒汉式改造(线程安全) 推荐指数:★★☆☆☆

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。
缺点:没有线程安全问题,但是有很大的性能问题,当多个线程同时到达getInstance()方法时,需要排队进入。

public class Singleton4 {

    private static Singleton4 instance;

    private Singleton4() {

    }

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

5.懒汉式改造(线程不安全) 推荐指数:☆☆☆☆☆

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。
缺点:线程不安全,还有性能问题!多个线程在synchronized那一行排队,进入代码块后一样会创建多个对象。

public class Singleton5 {

    private static Singleton5 instance;

    private Singleton5() {

    }

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

6.双重检查缺陷版(线程不安全) 推荐指数:☆☆☆☆☆

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。
缺点:线程不安全,这里的线程不安全要涉及到对象的创建过程和指令重排序。

public class Singleton6 {

    private static Singleton6 instance;

    private Singleton6() {

    }

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

详细讨论

这个优化我们利用了双重检测机制和同步锁,这种方式也称为双重同步锁单例模式,但是这个案例还是线程不安全的,大家通过代码层面的分析后,发现确实不会有线程安全问题,那问题出现在哪呢?这个其实要和对象创建步骤和Jvm指令重排挂钩,我们正常创建对象的指令步骤是这样的:

  1. memory = allocate() 分配对象的内存空间
  2. ctorInstance() 初始化对象
  3. instance = memory 设置instance指向刚分配的内存

但是因为JVM和cpu优化,发生了指令重排

  1. memory = allocate() 分配对象的内存空间
  2. instance = memory 设置instance指向刚分配的内存
  3. ctorInstance() 初始化对象

我们可以结合代码,假如A线程进入同步代码块执行instance = new Singleton6(),执行到“instance = memory 设置instance指向刚分配的内存”,这个时候B线程在第一次执行“if (instance == null)”,发现instance不为空,直接返回instance实例,其实线程B得到的这个实例并没有完全初始化(A还没有执行完对象的初始化步骤)就已经使用了。

关于对象创建过程可以参考 Java对象的创建、内存布局和访问定位

那如何禁止指令重排呢,很简单,用我们前面文章提到的volatile关键字就可以了

7.双重检查优化版(线程安全) 推荐指数:★★★★☆

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。
缺点:复杂。

public class Singleton7 {

    private volatile static Singleton6 instance;

    private Singleton6() {

    }

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

8.静态内部类方式 推荐指数:★★★☆☆

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题,线程安全。
缺点:没有太大缺点。

public class Singleton8 {

    private Singleton7() {
    }

    private static class SingletonInstance {
        private static final Singleton7 INSTANCE = new Singleton7();
    }

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

9.枚举单例 推荐指数:★★★★★

优点:使用到的时候才会创建对象,不会造成各种资源浪费问题,线程安全。
缺点:最优方案。

public class Singleton9 {

    private Singleton9() {
    }

    private enum SingletonEnum {
        /**
         * 枚举单例
         */
        SINGLETON;

        private Singleton9 singleton;

        SingletonEnum() {
            singleton = new Singleton9();
        }

        public Singleton9 getInstance() {
            return singleton;
        }
    }

    public Singleton9 getInstance() {
        return SingletonEnum.SINGLETON.getInstance();
    }
}

发布了112 篇原创文章 · 获赞 303 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_36221788/article/details/102948131