美文网首页
单例模式之懒汉式代码优化(双重检查)

单例模式之懒汉式代码优化(双重检查)

作者: 谜00016 | 来源:发表于2019-02-20 16:12 被阅读25次

问题分析

上篇文章,我们使用了synchronized关键字解决了多线程环境下的单例模式的线程安全问题。

/**
 * @Auther: ming.wang
 * @Date: 2019/1/6 19:25
 * @Description:
 */

public class LazySingleton {
    private static LazySingleton lazySingleton=null;
    private LazySingleton() {
    }

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

}

但同时也有个小小的缺憾,就是synchronized关键字开销比较大。本篇文章就来分析改如何优化上述代码。

优化

其实优化思路已经在标题中体现了,就是使用双重检查的方式来减少进锁的几率。闲言碎语不要讲,直接上代码

/**
 * @Author: ming.wang
 * @Date: 2019/2/20 14:45
 * @Description:
 */
public class LazyDoubleCheckSingleton {

    private volatile static LazyDoubleCheckSingleton instance=null;

    private LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance(){
        if (null==instance) {//第一个 if(instance==null),其实是为了解决代码中的效率问题,只有instance为null的时候,才进入synchronized的代码段,大大减少了几率。
            synchronized (LazyDoubleCheckSingleton.class) {
                if (null==instance) {//第二个if(instance==null),则是为了防止可能出现多个实例的情况。
                    instance=new LazyDoubleCheckSingleton();
                    /*
                    * 1.分配内存给这对象
                    * 2.初始化对象
                    * 3.设置instance指向刚刚分配的内存空间(执行完这步 instance才是非 null了)
                    * 其中2和3会指令重排序,执行顺序可能为123或132
                    * */
                }
            }
        }
        return instance;
    }
}

上述代码有几处我们需要分析一下

  • i. 双重检查的含义
    代码中我们使用了两处if (null==instance)空判断。第一个 if(instance==null),其实是为了解决代码中的效率问题,只有instance为null的时候,才进入synchronized的代码段,大大减少了执行synchronized的几率。第二个if(instance==null),则是为了防止可能出现多个实例的情况。

  • ii. volatile 关键字修饰instance
    为何要使用volatile 关键字修饰instance,网上这篇文章讲的很详细。
    简单来说,Java类初始化过程(本例中instance=new LazyDoubleCheckSingleton();)是非原子操作,会经历三个阶段,
    1.分配内存给这个对象,
    2.初始化对象,
    3.设置instance指向刚刚分配的内存空间(执行完这步 instance才是非 null了)。其中2和3会指令重排序,执行顺序可能为123或132。所以当如果执行顺序是132,那么当线程执行完3,此时对象已经不为空,但是并没有初始化。此时另一个线程抢占了CPU,那么执行getInstance()方法时就会直接返回instance(非 null 但却没有初始化),后续使用就会报错了。
    解决的方案就是使用volatile关键字修饰。此处他的作用主要是限制指令重排序。PS:有另一种说法是下面这样,希望知道的小伙伴告诉一下。

volatile阻止的不是singleton = new Singleton()这句话内部[1-2-3]的指令重排,而是保证了在一个写操作([1-2-3])完成之前,不会调用读操作(if (instance == null))。

修订

在《java并发编程的艺术》一书中,明确说明了,此处使用volatile关键字修饰的作用就是限制指令重排序(保证时序为123)。

相关文章

  • Java23种设计模式之「单例模式」

    单例模式 之 holder 模式 (推荐) 单例模式 之 饱汉模式(懒汉模式) 单例模式 之 双重锁检查 (Dou...

  • 单例模式之懒汉式代码优化(双重检查)

    问题分析 上篇文章,我们使用了synchronized关键字解决了多线程环境下的单例模式的线程安全问题。 但同时也...

  • 2018-05-14

    单利设计模式 懒汉式 单例模式 饿汉式 单利模式 懒汉式与饿汉式的区别: 双重锁式 单例模式 (DCL )

  • 大话设计模式之_单例模式

    大话设计模式之___单例模式 什么是单例模式单例模式有哪些(会顺带讲些懒汉式的性能优化)懒汉式与饿汉式的区别 什么...

  • kotlin实现单例模式

    1.懒汉式实现单例模式 2.线程安全懒汉式实现单例模式 3.双重校验懒汉式实现单例模式 4.静态内部类方式实现单例模式

  • 项目实战—那些年常用的单例模式

    常见的单例模式:饿汉式、懒汉式、双重检查锁模式、静态内部类实现单例模式、枚举单例模式,本文重点是在项目中如何实现上...

  • 设计模式小结

    单例模式 单例模式主要包括懒汉式、饿汉式、双重检查锁、静态内部类、枚举类。注意的点:构造方法为private, 变...

  • 尚学堂260课到289课23种设计模式

    单例模式_应用场景_饿汉式_懒汉式 262课单例模式_双重检查锁式_静态内部类式 270课_适配器模式_对象适配器...

  • 单例(Singleton)

    单例设计模式 单例模式的创建 饿汉式1 饿汉式2 懒汉式 优化后的懒汉式(线程安全): 饿汉式与懒汉式区别 单例模...

  • Kotlin 的单例模式

    Kotlin 的单例模式(5种) Kotlin 的5种单例模式: 饿汉式 懒汉式 线程安全的懒汉式 双重校验锁式 ...

网友评论

      本文标题:单例模式之懒汉式代码优化(双重检查)

      本文链接:https://www.haomeiwen.com/subject/qfucyqtx.html