Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
445 views
in Technique[技术] by (71.8m points)

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的结果

image.png

执行 sout的结果
image.png


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

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

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

        public  volatile boolean flag = false;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
...