关于双重检测(工作内存、主内存)
来源:3-4 线程安全性-可见性
![](http://img1.sycdn.imooc.com/user/545865f0000198ee02200220-100-100.jpg)
慕神2874530
2019-05-07
老师,您好,我现在有一点儿懵逼,工作内存的对变量副本的修改什么时候会同步会主内存呢?
比如双重检测实现的单例模式:
public class Util {
private static Util instance;
public static Util getInstance() {
if (instance == null) {
synchronized (Util.class) {
if (instance == null) {
instance = new Util();
}
}
}
return instance;
}
public static void main(String[] args) {
Util.getInstance();
}
}
这里instance变量需要volatile修饰是因为instance = new Util();可能发生指令重排。但是我现在一想,即使A线程在执行instance = new Util();操作的时候,发生了重排,先把内存空间地址设置到了instance变量,然后再初始化内存空间。但是因为给instance变量赋值的操作是在A线程内发生的,这时赋值的目标应该是instance变量在A线程工作内存的副本才对啊,当B线程来获取instance的时候,如果A线程没有把最新值(不论是有没有被初始化完成的对象)同步到主内存,那么B线程从主内存获取instance的结果应该也是空才对啊,就不会出现获取到一个没有初始化好的对象的情况啊。
谢谢老师解答!
1回答
-
你好,你的假设是有问题的。
这段代码可能执行出错的场景在于:首先是a线程设置了instance在内存里的空间地址,然后分配相关内存空间。在设置完instance空间地址时,其他线程就已经可以看到了,而且这时instance已经不为空了。b线程如果刚好在这个节点调用这个方法时,判断instance不为空,就会直接返回这个实例,b线程不会继续做初始化,这时instance就会被其他方法拿到并使用,而由于instance并没有分配实际的内存工具(本身分配可能很慢,即a线程第二步一直没做完),这时实际使用instance就会出错了,因为没有实际分配内存。
这段代码不会肯定出问题,而是只有在特殊的场景下才会触发一些异常的可能。你的例子如果没对上这种特殊的场景,就看不出问题所在了052019-05-08
相似问题