Java指令重新排序/线程缓存

jn1*_*1kk 3 java multithreading caching

读一本书,这个代码出现了:

public class Test {

    private static boolean ready = false;
    private static int number = 0;

    public static class ListenerThread extends Thread {

        public void run() {

            while(!ready) {
                Thread.yield();
            }
            System.out.println(number);

        }

    }

    public static void main (String[] args) {

        new ListenerThread().start();
        number = 10;
        ready = true;

    }

}
Run Code Online (Sandbox Code Playgroud)

笔者相对较快地提到了我感到惊讶的要点.

  1. 他们说ListenerThread可能永远不会终止.我想了几天(在我的脑后),我唯一的结论是它可能被ListenerThread缓存.真的吗?将readyvolatile设置为解决问题(因为它不应该再缓存它)?

  2. 他们还说该程序可能会打印0.我现在明白Java可能会重新排序指令,因此在更改数字之前准备就绪为另一个线程.有没有任何方法(技术),除了将这些指令放在同步块中解决问题(在中央锁定值上)?我在想也许实现notify()/ wait(),但我觉得它会遭受同样的后果.避免这个问题的最佳方法是什么?

谢谢!

编辑:

我只是觉得我已经阅读了很多代码,并且很少有人为防止在多个线程中重新排序而烦恼.这有多常见?

Pet*_*rey 8

我唯一的结论是它可能被ListenerThread缓存.真的吗?准备挥发性会解决问题(因为它不应该再缓存它)?

不仅缓存,而且JIT可以在线程永远不会更改它的基础上内联值.即它变得硬编码.

使用volatile可以防止这样的假设.它会强制它每次都读取缓存一致的副本.

我现在明白Java可能会重新排序指令,

不仅是Java,而且CPU可以重新排序指令.JIT知道CPU可以执行此重新排序和它很少需要的AFAIK,因为它假设CPU将做得很好.

BTW访问volatile变量也会阻止指令重新排序,因此readyvolatile可以解决这两个问题.