欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

可见性(visibility)的问题是Java多线程应用中的错误的根源

程序员文章站 2022-04-20 19:00:03
...

看下面一段代码,预想的输出结果为 42

public class NoVisibility {
    private static boolean ready;
    private static int number;

    private static class ReaderThread extends Thread {
        public void run() {
            while (!ready)
                Thread.yield();
            System.out.println(number);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}


此段代码有可能输出 0 或者 reader线程死循环
导致这种错误出现的原因

  • CPU 内部的缓存:现在的CPU一般都拥有层次结构的几级缓存。CPU直接操作的是缓存中的数据,并在需要的时候把缓存中的数据与主存进行同步。因此在某些时刻,缓存中的数据与主存内的数据可能是不一致的。某个线程所执行的写入操作的新值可能当前还保存在CPU的缓存中,还没有被写回到主存中。这个时候,另外一个线程的读取操作读取的就还是主存中的旧值。
  • CPU的指令执行顺序:在某些时候,CPU可能改变指令的执行顺序。这有可能导致一个线程过早的看到另外一个线程的写入操作完成之后的新值。
  • 编译器代码重排:出于性能优化的目的,编译器可能在编译的时候对生成的目标代码进行重新排列。


因为在没有同步机制的下,语句的执行顺序不能得到保证。尽管我们得代码number的复制在ready之前,但这并不能保证jvm内部执行也会按照这个顺序,导致读线程出现错误。
更详细内容请参考:Java深度历险(三)——Java线程​:基本概念、可见性与同步