原文 完美世界 (abstractsoulworld.top)
·这个是有意思的问题--单例模式是否需要volatile修饰?
不用volatile修饰在单核情况下不会有问题,及时是多核下也要很大并发下才可能偶现。
因为涉及到指令层次---new 不是原子操作(指令层,在jvm层面可以看作原子操作),它分3个指令:
1、 new ---堆上分配内存
2、invokespecial T .init ----初始化
3、 astore -----堆对象绑定(也就是对象的指向地址)
2初始化与 与3是可以位置互换的,会指令重排。这个时候问题来了:
先看一下单例模式的dcl写法(double check lock)---
public class Tt{
private static Tt tt; // 这个 static 可以去掉,因为dcl是懒汉式, ps 饿汉式写法就一定的加上,不然 死循环。
private Tt (){}
public Tt getObj(){
if(null==tt){
synchronized(Tt.class){
if(null==tt){ //这个双重检测就是为了并发大的时候,2个线程同时过来第一道检测,
tt=new Tt(); //不加 volatile 问题就来了,当指令变成 1-3-2 时,1-3的时候 new 对象其实已经完成了 ,在执行 2指令的时候,突然来了个线程(这个二五仔线程),他一看,咦~,有new好的,直接拿去用了,用完之后,2指令才执行完,这就导致,二五仔线程,用错了对象,。。,,,,,,,,
}
return tt;
}
}
}
}
在写个 饿汉式 :
public class Tt{
private static Tt tt=new Tt(); //类加载的时候就实例化好,,,,,
pirvate Tt(){}
public Tt getObj(){
return tt;
}
}