首先给出结论:双重检查锁是需要加volatile的。
先介绍下双重检查锁:
如上图,是单例设计模式中的懒汉式单例模式。其实在getInstance()方法前加上锁也能保证单例, 但直接加锁颗粒度太粗了。所以就出现了双重检查,通过第二次检查保证在多线程的情况下仍能保持单例。
为了得出上面结论,还需要了解一下对象的创建过程,如下图:
第一条指令是在内存中开辟空间,然后对对象进行半初始化,此时m得到了一个默认的值,在第一条指令完成时,此时的m是0,而不是8。
第二条指令是对对象进行初始化,m的值为8。
第三条指令用于建立关联对象t与m之间的关联。
问题的出现是因为在创建对象的时候,第二条指令和第三条指令会进行重排序。假设此时线程1通过第二次检查,在创建对象的过程中,第二条指令和第三条指令出现重排序,此时instance指向的是一个半初始化的对象。如果在这个时候线程2进来了,在执行第一次检查的时候发现instance并非为空,这时就直接返回了半初始化的instance,从而会出现问题。
而volatile的作用是保持可见性和防止指令重排序。所以在声明instance的时候需要加上volatile关键字。