我想亲自尝试Java lang spec example,但显然我有些不明白。我的理解是,易失性计数器的递增顺序应该与代码中出现的顺序相同。 “令人惊讶的是”我得到一个随机计数器值,因为一个计数器有时更少,相等和更大。 有没有人可以解释我错过的东西?
下面的代码和输出:
public class C {
private static volatile int i = 0;
private static volatile int j = 0;
static void one() {
i++;
j++;
}
static void two() {
int a = i;
int b = j;
if(a < b)
System.out.println(a + " < " + b);
if(a > b)
System.out.println(a + " > " + b);
if(a == b)
System.out.println(a + " = " + b);
}
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(true)
one();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while(true)
two();
}
});
t1.start();
t2.start();
Thread.sleep(5000);
System.exit(0);
}
}
输出
214559700 > 214559699
214559807 > 214559806
214559917 > 214559916
214560019 = 214560019
214560137 > 214560136
214560247 = 214560247
214560349 > 214560348
214560455 = 214560455
214560561 > 214560560
214560670 = 214560670
214560776 = 214560776
214560886 > 214560885
214560995 = 214560995
214561097 < 214561098
答案 0 :(得分:1)
对于所有三种情况,假设我们从i = 0
和j = 0
开始......一个()和两个()都可以执行两个操作,但是一个和两个之间的顺序是未定义:
a == b
two() loads i (a = 0)
two() loads j (b = 0)
one() increments i (i = 1)
one() increments j (j = 1)
a&gt; B'/强>
one() increments i (i = 1)
two() loads i (a = 1)
two() loads j (b = 0)
one() increments j (j = 1)
a&lt; b (稀有)
two() loads i (a = 0)
one() increments i (i = 1)
one() increments j (j = 1)
two() loads j (b = 1)
答案 1 :(得分:0)
重要的是要注意线程可以通过多种方式进行交错。由于您要将i
和j
复制到a
和b
,因此您可以修改<{1}}和i
之间的<{1}} / em>将j
复制到i
,将a
复制到j
。例如,这种痕迹可以解释你的输出:
T2:a = i,b = j
b
T2:a = i,b = j
214559700 > 214559699
T2:a = i,b = j
214559807 > 214559806
T2:a = i,b = j
214559917 > 214559916
答案 2 :(得分:0)
对i和j的访问不同步,因此,以下所有情况都可能发生:
答案 3 :(得分:0)
当其中一个线程刚刚完成递增i
并希望开始递增j
时,另一个线程可能已经设置了int a
和b
,因此导致不同的价值观。
volatile
具有不同的用途,因为我认为你认为它有用。实质上,volatile
用于表示变量的值将被不同的线程修改。 volatile修饰符保证读取字段的任何线程都将看到最近写入的值
声明一个易变的Java变量意味着:
synchronized
块中一样,自身同步。当您想要从不同的线程而不是不同的成员访问相同的volatile成员时,volatile
的使用会变得更加清晰。
答案 4 :(得分:0)
如果我们先阅读j
,
static void two() {
int b = j;
int a = i;
然后保证a> = b。