一、问题
public class TestVolatile implements Runnable {
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag---" + flag);
}
public static void main(String[] args) {
TestVolatile tv = new TestVolatile();
new Thread(tv).start();
while (true) {
// System.out.println("tv.isFlag()---" + tv.isFlag());
if (tv.isFlag()) {
System.out.println("hello main!");
break;
}
}
}
}
示例是实现了 Runnable 的自定义线程类,run() 将 flag 变为 true。main() 中启动子线程,主线程 while(true) 中判断 flag 为 true 输出“hello main!”。然而“hello main!”永远不会输出。原因是:
主线程中if (tv.isFlag())
感知不到子线程中 flag 的变化。两个线程的数据是不会相互干扰的。也就是说这两个线程里面都存在一个 flag 的副本。真正的 flag 这个变量存放在主内存中,两个线程的工作内存中的 flag 变量只是副本。
二、synchronized 影响内存的可见性
放开代码中的注释行,“hello main!”输出了。这是为什么?
主线程感知到了子线程对 flag 的改动,说明这条打印语句已经影响到了内存可见性。如何影响的呢?答案就在源码里面:原来 println 有一个上锁的操作。使用了 synchronized 上锁会做以下操作:
- 获得同步锁;
- 清空工作内存;
- 从主内存拷贝对象副本到工作内存;
- 执行代码(计算或者输出等);
- 刷新主内存数据;
- 释放同步锁。
网友评论