volatile测试没有达到JLS中之前发生的特性

时间:2015-04-09 01:38:21

标签: volatile happens-before

运行主

public class ThreadTest {
volatile int p = 0, q = 0;
  public void test() throws InterruptedException {
        Thread writeThread = new Thread(){
            public void run(){
                while (!isInterrupted()) {
                    p++;
                    q++;
                }
            }
        };
        Thread readThread = new Thread(){
            public void run(){
                while (!isInterrupted()) {
                    //p should not be less than q
                    if(p<q){
                        System.out.println("happen before violation p = " + p + ";q = " + q);
                    }
                }
            }
        };
        writeThread.start();
        readThread.start();
        Thread.currentThread().sleep(2);
        writeThread.interrupt();
        readThread.interrupt();
  }

  public static void main(String[] args) throws InterruptedException {
    new ThreadTest().test();
  }
}

输出

在违规之前发生p = 736; q = 827
在违规之前发生p = 4635; q = 4657
在违规之前发生p = 6421; q = 6440
在违规之前发生p = 8719; q = 8803

1 个答案:

答案 0 :(得分:0)

你应该阅读 p AFTER q ,以确保它们的值是“不低于”的顺序:

int q_value = q; // Read 'q' once
int p_value = p; // Read 'p' AFTER q
if(p_value < q_value) // ... happens-before violation

在这种情况下,只有 q 需要易变修饰符, p 可以省略它而不会违反约束。

在原始代码中,没有什么能阻止编译器在 q 之前读取 p 。因此,readThread可以在writeThread的第736次迭代中看到 p 值,但是从第827次迭代中看到 q 值。 或者readThread可以从第100次迭代开始(即p = 100)看到 p 值,但是从该迭代结束时看到 q 值(即是,q = 101)。