考虑JLS section on volatile fields
中的以下程序class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
考虑两个线程同时执行方法one()
和two()
。
JLS声明如下:
这允许方法一和方法二同时执行,但是 保证访问i和j的共享值 与它们出现的次数完全相同,顺序完全相同 在每个线程执行程序文本期间发生。 因此,j的共享值永远不会大于i的共享值, 因为对i的每次更新都必须反映在i的共享值中 在更新到j之前发生。但是,任何给定的都是可能的 方法二的调用可能会观察到j的值很多 大于i观察到的值,因为方法一可能是 在方法二取出之间执行多次 i的值和方法二取值j的时刻。
我对上面的引文感到很困惑,因为它说了两个相互矛盾的陈述:
j
的共享值从不大于i
的共享值。
(强调我的)。
j
的值远远超过i
观察到的值。
第一个语句对我有意义,因为如果我们将程序顺序规则(i++
之前发生的j++
)与volatile的内存可见性保证(之前发生)相结合,我可以理解为什么j
的值不能超过i
。但我无法看到j
的价值如何远远超过i
。
请你帮我理解这部分。
答案 0 :(得分:3)
在任何给定时刻,j
的实际值绝不会大于i
的实际值。但是当声明
System.out.println("i=" + i + " j=" + j);
已执行,i
和j
未在同一时间进行评估。在j
之后评估i
。评估i
时,j
小于或等于i
。但是,在评估j
时,另一个线程可能多次调用方法one()
,因此i
和j
可能会多次递增。因此j
仍为<= i
,但打印的内容可能是
i=4 j=257
因为它实际上是
at time t0, i=4
at time t1, j=257