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的示例中,我将同步关键字添加到方法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

....

最佳答案

这是可能的,并在您提到的链接中进行了描述。在该段的末尾。


  但是,方法二的任何给定调用都可能会观察到j的值远大于观察到的i的值,因为方法二可能在方法二获取i和i的值之间被执行多次。方法二获取j值的时刻。


因此,two()方法按照代码中的确切顺序依次读取i和j。但是在读取之间有一个one()方法调用,其结果为(4998,5000)

10-04 11:45