Java单例模式双重检查锁定为什么使用volatile关键字

双重检查锁定代码如下:

public class Singleton{   
    // 静态属性,volatile保证可见性和禁止指令重排序
    private volatile static Singleton instance = null; 
    // 私有化构造器  
    private Singleton(){}   

    public static  Singleton getInstance(){   
        // 第一重检查锁定
        if(instance==null){  
            // 同步锁定代码块 
            synchronized(Singleton.class){
                // 第二重检查锁定
                if(instance==null){
                    // 注意:非原子操作
                    instance=new Singleton(); 
                }
            }              
        }   
        return instance;   
    }   
}

volatile作用:以下会涉及到Java内存模型的知识

禁止指令重排序:

new singleton()操作在Java中不是一个原子性的操作。这个动作大概分了3步

1.申请一个内存区域(空白内存)

2.调用构造方法等对singleton进行初始化(写内存)

3.将变量指针指向该对象内存区域(变量声明)

那么问题来了。虽然双重验证锁保证了进入锁时进行判断。但如果线程1在进行new操作时,由于指令重排序先执行了1、3而没有执行初始化的步骤。此时线程2进来判断instance非null直接返回了。那么线程2获得的是个不完整的对象,使用时就会报错。

保证可见性:

线程A在自己的工作线程内创建了实例,但此时还未同步到主存中;此时线程B在主存中判断instance还是null,那么线程B又将在自己的工作线程中创建一个实例,这样就创建了多个实例。

 

顺便提一下,volatile禁止指令重排序只能保证volatile修饰的代码之后的代码不会在它之前执行。
 

你可能感兴趣的:(Java单例模式双重检查锁定为什么使用volatile关键字)