美文网首页
System.out.println()影响内存的可见性

System.out.println()影响内存的可见性

作者: Djbfifjd | 来源:发表于2021-03-02 21:22 被阅读0次

    一、问题

    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 上锁会做以下操作:

    1. 获得同步锁;
    2. 清空工作内存;
    3. 从主内存拷贝对象副本到工作内存;
    4. 执行代码(计算或者输出等);
    5. 刷新主内存数据;
    6. 释放同步锁。

    相关文章

      网友评论

          本文标题:System.out.println()影响内存的可见性

          本文链接:https://www.haomeiwen.com/subject/mowxqltx.html