Java中线程间可见性错误分析

发布于 2022-09-12 03:25:45 字数 1333 浏览 24 评论 0

题目描述

在验证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的结果

image.png

执行 sout的结果
image.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

晚雾 2022-09-19 03:25:45

主要原因是执行System.out.println和其他语句相比而言,
非常慢,涉及很多的内部操作, 造成 CPU 缓存失效。所以起的作用相当于让主线程终于有机会看到 flag 发生了变化。

可以加上 count 比较一下(我机器上有输出时循环执行70399次,没有输出时循环执行了801053907次)。

最终多线程共享变量还是要用volatile关键字来处理可见性的问题:

        public  volatile boolean flag = false;
拥抱影子 2022-09-19 03:25:45

Sout本质是同步执行的,自行看JDK源码就知道了,相当于一种变相的部分同步。

要打印,建议用log4j, logback等日志框架,你会发现注不注释结果就差不多了。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文