java中的双重验证为何要用volatile

一、volatile+synchronized实现方案

package com.example.myapplication;

public class TestSingleton {

    private static volatile TestSingleton testSingleton;

    public static TestSingleton getInstance(){
        if(testSingleton == null){
            synchronized (TestSingleton.class){
                if(testSingleton == null){
                    testSingleton = new TestSingleton();
                }
            }
        }

        return testSingleton;
    }
}
原因:volatile防止指令重排序

testSingleton = new TestSingleton();这一行代码创建了一个对象,创建过程可以分解为如下3行伪代码。

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

其中第2和3之间,可能会被重排序。因为java中允许那些在单线程内,不会改变单线程程序执行结果的重排序。上面伪代码2和3之间虽然被重排序,单不会影响最终结果。2、3重排序之后的执行时序如下。

memory = allocate();  //1.分配对象的内存空间
testSingleton= memory;  //3.设置testSingleton指向刚分配的内存地址  
//注:此时对象还没有被初始化!                            
ctorInstance(memory);  //2.初始化对象

因此,如果发生重排序,另一个并发执行的线程就有可能判断testSingleton不为null。然后线程接下来将访问这个对象,但此时对象还没有被初始化!所以我们要使用volatile关键字防止指令重排序。

你可能感兴趣的:(java中的双重验证为何要用volatile)