检查非易失性变量变化的Java线程似乎需要永远

Shi*_*gon 1 java multithreading volatile

我很抱歉,如果我对此做了一件坏事,但我有一个问题,这是这个问题的衍生产品:

为什么java 5+中的volatile不会将变量的缓存副本与主内存同步?

基本上,我想看看当volatilea变量中消除时会发生什么.这是原始问题的代码,应用了我的修改:

public class Test {
    //volatile static private int a;
    static private int a;
    static private int b;
public static void main(String [] args) throws Exception {
    for (int i = 0; i < 100; i++) {
        new Thread() {

            @Override
            public void run() {
                int tt = b; // makes the jvm cache the value of b

                while (a==0) {

                }
                //some threads never get here (past the a==0 loop)

                if (b == 0) {
                    System.out.println("error");
                }
            }

        }.start();
    }

    b = 1;
    a = 1;
}
}
Run Code Online (Sandbox Code Playgroud)

在我的笔记本电脑上发生的事情(Win 7 64,JVM build 1.7.0_04-b22)是没有的volatile,代码似乎永远运行(运行20分钟).添加一些控制台输出告诉我,虽然大多数的100个线程的根本终于看到了变化a,从01,总有几个左侧(小于10)继续做a==0循环.

我的问题是:这些线程最终会看到这种变化吗?如果是的话,与大多数相似的线程相比,花费数倍于数千倍的时间是正常的吗?怎么会?

Mar*_*nik 7

这根本不是关于变量传播的速度; 机器代码可以使得甚至不尝试存储器写入.该值可以驻留在寄存器中.

无论如何,我的建议是不要探索破解Java代码的行为:无论如何它总是会有所不同.相反,学习如何正确编写同步程序.详细研究Java内存模型并了解其保证.JMM的保证远远不同于支持这些保证的实际JVM实现代码,而JMM是专门为JVM提供应用各种优化的自由而编写的.

作为一个特别尖锐的例子,破坏的代码的行为可以在其执行过程中发生变化,因为解释的或C1代码正在与C2代码及时替换.运行您引用的程序无需学习任何内容.