Java中线程间可见性错误分析
题目描述
在验证volatile关键字时,发现了这个场景:代码里注释行执行和不执行,最后的结果不一样。
当注释掉打印的信息时,业务逻辑会死循环执行,可以理解
当释放掉注释之后,业务逻辑 就能读取到 子线程修改的值
题目来源及自己的思路
相关代码
public class VolatileTest {
public static void main(String[] args) {
VolatileThread thread = new VolatileThread();
thread.start();
while (true) {
// System.out.println("thread.isFlag():" + thread.isFlag());
if (thread.isFlag()) {
System.out.println("----------------------");
break;
}
}
}
public static class VolatileThread extends Thread {
public boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag= " + flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
}
你期待的结果是什么?实际看到的错误信息又是什么?
注释 sout的结果
执行 sout的结果
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
主要原因是执行
System.out.println
和其他语句相比而言,非常慢,涉及很多的内部操作, 造成 CPU 缓存失效。所以起的作用相当于让主线程终于有机会看到 flag 发生了变化。
可以加上 count 比较一下(我机器上有输出时循环执行70399次,没有输出时循环执行了801053907次)。
最终多线程共享变量还是要用
volatile
关键字来处理可见性的问题:Sout本质是同步执行的,自行看JDK源码就知道了,相当于一种变相的部分同步。
要打印,建议用log4j, logback等日志框架,你会发现注不注释结果就差不多了。