虽然SO和其他地方有很多关于之前发生过的关系的帖子,但我很难找到对我的问题的确切答案。
考虑两个Java线程:
最初是flag == false
和data == 0
T1
data = 42;
synchronized(m) {
flag = true;
}
T2
boolean f;
synchronized(m) {
f = flag;
}
if (f) {
int x = data;
}
根据上面的代码,我相信f
可以分配值true
或false
,没有保证。这是对的吗?
现在,如果两个synchronized
语句更改为synchronized(flag)
,我认为指令flag = true
将始终发生在指令f = flag
之前,因此f
}将始终分配值true
。这是对的吗?
答案 0 :(得分:6)
不,同步不保证首先Thread
到达那里。仅保证多一个Thread
无法一次访问同步块。
将synchronized
区块视为门上有锁的房间。我们不知道谁会首先到达门口,但一旦他们这样做,他们会进门并锁上门。
其他人必须等到房间里的人准备离开并打开门。一旦发生这种情况,每个人都会再次参加比赛。
这完全取决于您将Thread
设置为关闭的顺序。但即便如此,由于JVM可能会随机暂停Thread
和Thread
s yield
,因此无法保证。在类比中 - 领先到门的人可能会在香蕉皮上绊倒。不太可能,但总是可能的。
如果您想获得保证,则需要wait
/ notify
- 以便阅读线程检查flag
,如果它是false
,则暂停一个循环。
写作线程然后设置flag
并通知锁定监视器唤醒读取线程。
以下是使用Java 5中的Lock
和Condition
api的示例。我并不是说 使用优先于{{1} }和synchronized
/ wait
- 这只是我改编的一个例子。
notify
获取Reader
,然后在循环中检查lock
标志。如果该标志为ready
,则条件为false
。这会以原子方式释放await
并暂停lock
。
Thread
同时获取Writer
并设置lock
和data
标志。然后,它会调用ready
并释放signalAll
。
这会唤醒lock
,然后将Reader
读为ready
,然后转到true
语句。
输出始终为print
(从不42
)。
-1