volatile例子(在JLS8 / 8.3.1.4 volatile字段中)不起作用?

时间:2017-06-12 16:26:14

标签: java concurrency volatile jls

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4

Java语言规范8 / 8.3.1.4易失性字段

volatile example

问题:

在volatile的示例中,我将synchronized关键字添加到方法two(),以避免在方法one()期间执行two()

但我仍然注意到j大于i:为什么?

注意:

我使用Java HotSpot 1.8.0_112。

If you can not noticed j is larger than i, please set testVolatile()/num to a larger number.

我的演示:

public class VolatileDemo {

    static volatile int i = 0, j = 0;

    static void one() {
        i++;
        j++;
    }

    static synchronized void two() {
        if (i != j)
            System.out.println("i=" + i + " j=" + j);
    }

    static void testVolatile() {
        int num = 5000;
        for (int i = 0; i < num; i++) {
            new Thread(new Runnable() {
                public void run() {
                    one();
                }
            }).start();
        }
        for (int i = 0; i < num; i++) {
            new Thread(new Runnable() {
                public void run() {
                    two();
                }
            }).start();
        }
    }

    public static void main(String[] args) {
        testVolatile();
    }
}

我的结果:

i = 4996 j = 4998

i = 4998 j = 5000

i = 4998 j = 5000

...

1 个答案:

答案 0 :(得分:2)

It's possible and it's described in the link you mentioned. It's at the end of the paragraph.

It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.

So two() method reads i and then j with the exact order as in your code. But there are a cople of one() method calls between that reads which gives the result of (4998, 5000)