重点代码
private volatile Test_Object obj;
public void test(){
if(obj == null){
synchronized (Test_Object.class){
if(obj == null){ //DCL
try{
obj = new Test_Object();
} catch(Exception e){
//do something
}
}
}
}
}
为什么 Test_Object 的 obj 要用volatile修饰?
在于volatile禁止重排序的这一特性。而在以上的DCL中,需要对obj对象的初始化禁止重排序。
对象初始化的主要3步
1.分配内存后,会有一个初始值(就像 int 类型赋值0)。
2.执行构造,将初始化的实际值赋上。
3.将该块内存地址指向(链接)obj。
综述
volatile的作用就是为了防止obj初始化时,执行步骤2,3的两条指令重排序。
因为步骤3先执行,此时 obj 就不为 null(但是值却是个系统赋予初始值,并非实际赋值),这会让线程误会obj对象已创建,最终导致obj的实际赋值失败,当前值只是个默认初始化值,线程拿一个半初始化的对象去使用。