Java发生在关系之前

时间:2013-04-26 14:55:11

标签: java synchronization

虽然SO和其他地方有很多关于之前发生过的关系的帖子,但我很难找到对我的问题的确切答案。

考虑两个Java线程:

最初是flag == falsedata == 0

T1

data = 42;
synchronized(m) {
  flag = true;
}

T2

boolean f;
synchronized(m) {
  f = flag;
}
if (f) {
  int x = data;
}

根据上面的代码,我相信f可以分配值truefalse,没有保证。这是对的吗?

现在,如果两个synchronized语句更改为synchronized(flag),我认为指令flag = true将始终发生在指令f = flag之前,因此f }将始终分配值true。这是对的吗?

1 个答案:

答案 0 :(得分:6)

不,同步不保证首先Thread到达那里。仅保证多一个Thread无法一次访问同步块。

synchronized区块视为门上有锁的房间。我们不知道谁会首先到达门口,但一旦他们这样做,他们会进门并锁上门。

其他人必须等到房间里的人准备离开并打开门。一旦发生这种情况,每个人都会再次参加比赛。

这完全取决于您将Thread设置为关闭的顺序。但即便如此,由于JVM可能会随机暂停ThreadThread s yield,因此无法保证。在类比中 - 领先到门的人可能会在香蕉皮上绊倒。不太可能,但总是可能的。

如果您想获得保证,则需要wait / notify - 以便阅读线程检查flag,如果它是false,则暂停一个循环。

写作线程然后设置flag并通知锁定监视器唤醒读取线程。

以下是使用Java 5中的LockCondition api的示例。我并不是说 使用优先于{{1} }和synchronized / wait - 这只是我改编的一个例子。

notify获取Reader,然后在循环中检查lock标志。如果该标志为ready,则条件为false。这会以原子方式释放await并暂停lock

Thread同时获取Writer并设置lockdata标志。然后,它会调用ready并释放signalAll

这会唤醒lock,然后将Reader读为ready,然后转到true语句。

输出始终为print(从不42)。

-1