一:哪出问题了,单例模式double-check 情景:
二:众(wo)所(gang)周(zhi)知(dao),JVM加载一个class。对静态变量操作有两个过程,一个是linking过程的preparation(给静态变量赋默认值),另一个是在initializing的时候给静态变量赋相应值。
三:我们看一下对于一个没有加载到内存的class,new的过程有哪些步骤。
看右边汇编(不懂汇编没关系,我学过汇编,我也看不懂这个。。。),也就是说new的过程分3步
- new#2<T> 开辟内存,给静态变量赋默认值
//dup是引用地址复制一份 - invokespecial #3<T.<init>>,给静态变量
- astroe_1 给t地址引用
四:指令重排序以及引发的问题
上面我们说了new的三个步骤,但JVM里面会发生一个指令重排序的优化。就是astore_1会在 invokespecial #3<T.<init>>之前执行。假设我们第一次加载的时候,执行了1 2 4之后(发生了重排),t已经不是null了。其他线程这个时候检测到t有地址引用不是null了,直接就给他返回了。 但t这个时候并没有完成初始化。
五:解决方法,将INSTANCE这个变量生命成volitale
volitale不仅是线程之间可见,而且禁止指令重排序。
网友评论