[英]Java happens-before relationship
Although there are a lot of posts on SO and elsewhere about the happens-before relationship, I am having a surprisingly hard time finding a definitive answer to my question. 虽然SO和其他地方有很多关于之前发生过的关系的帖子,但我很难找到对我的问题的确切答案。
Consider the two Java threads: 考虑两个Java线程:
initially, flag == false
and data == 0
最初,
flag == false
和data == 0
T1 T1
data = 42;
synchronized(m) {
flag = true;
}
T2 T2
boolean f;
synchronized(m) {
f = flag;
}
if (f) {
int x = data;
}
According to the code above, I believe f
could either be assigned the value true
or false
, there is no guaruntee. 根据上面的代码,我相信
f
可以被赋值为true
或false
,没有guaruntee。 Is this correct? 它是否正确?
Now, if the two synchronized
statements were changed to synchronized(flag)
, I think the instruction flag = true
will always happen before the instruction f = flag
, and thus f
will always be assigned the value true
. 现在,如果两个
synchronized
语句被更改为synchronized(flag)
,我认为指令flag = true
将始终发生在指令f = flag
,因此f
将始终被赋值为true
。 Is this correct? 它是否正确?
No, synchronized make no guarantees about which Thread
gets there first. 不,同步不保证首先到达哪个
Thread
。 In only guarantees that more that one Thread
cannot access the synchronized block at a time. 仅保证多一个
Thread
不能一次访问同步块。
Think of a synchronized
block as a room with a lock on the door. 将
synchronized
块视为门上有锁的房间。 We have no idea who will get to the door first, but once they do they go in and lock the door. 我们不知道谁会首先到达门口,但一旦他们这样做,他们就会进门并锁上门。
Other people must wait until the person in the room is ready to leave and unlocks the door. 其他人必须等到房间里的人准备离开并解锁门。 Once that happens everyone races to get in the door again.
一旦发生这种情况,每个人都会再次参加比赛。
It all depends on the order in which you set your Thread
s off. 这一切都取决于您关闭
Thread
的顺序。 But even then there are no guarantees as the JVM may suspend Thread
s and Thread
s yield
to one-another randomly. 但即便如此,也没有任何保证,因为JVM可能会随机地暂停
Thread
和Thread
的yield
。 In the analogy - the guy in the lead to get to the door might trip on a banana peel. 在类比中 - 领先到门的人可能会在香蕉皮上绊倒。 No likely, but always possible.
不太可能,但总是可能的。
If you want to have guarantees then you need to wait
/ notify
- so that the reading thread checks the flag
, and if it's false
, suspends itself in a loop. 如果你想要保证,那么你需要
wait
/ notify
- 以便读取线程检查flag
,如果它是false
,则在循环中挂起自己。
The writing thread then sets the flag
and notifies the lock monitor which wakes the reading thread. 写入线程然后设置
flag
并通知锁定监视器唤醒读取线程。
Here is an example using the Lock
and Condition
api from Java 5. I'm not saying that you have to use that in preference to synchronized
and wait
/ notify
- it's just an example I had lying around that I adapted. 下面是一个使用Java 5中的
Lock
和Condition
api的示例。我并不是说你必须优先使用它来synchronized
和wait
/ notify
- 这只是我躺在我适应的一个例子。
The Reader
acquires the lock
and then checks the ready
flag in a loop. Reader
获取lock
,然后在循环中检查ready
标志。 If the flag is false
it await
s on the condition. 如果该标志为
false
则await
该条件。 This atomically releases the lock
and suspends the Thread
. 这会以原子方式释放
lock
并挂起Thread
。
The Writer
meanwhile acquires the lock
and sets the data
and the ready
flag. Writer
同时获取lock
并设置data
和ready
标志。 It then calls signalAll
and releases the lock
. 然后它调用
signalAll
并释放lock
。
This wakes the Reader
which then reads the ready
as true
and proceeds to the print
statement. 这会唤醒
Reader
,然后读取ready
为true
并继续执行print
语句。
The output will always be 42
(never -1
). 输出将始终为
42
(从不为-1
)。
public class App {
static volatile boolean ready = false;
static volatile int data = -1;
private static class Reader implements Runnable {
private final Lock lock;
private final Condition condition;
public Reader(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
try {
while (!ready) {
try {
condition.await();
} catch (InterruptedException ex) {
//oh well
}
}
System.out.println(data);
} finally {
lock.unlock();
}
}
}
private static class Writer implements Runnable {
private final Lock lock;
private final Condition condition;
public Writer(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
try {
data = 42;
ready = true;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
executorService.execute(new Reader(lock, condition));
executorService.execute(new Writer(lock, condition));
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.