不同的监视器之间没有同步关系。
在获取锁和随后的执行之间存在发生前的关系,在执行和随后的锁释放之间存在发生前的关系。
如果一个线程在另一个线程离开同步块之后进入同步块,则在较早线程上执行同步块和在后线程上执行同步块之间可能存在先发生关系。
您只能确定同步块是否或何时不与 synchronizes-with 关系同时运行。没有这种关系,你就会有数据竞赛。
如果您显示的代码是线程之间的全部,则没有同步关系,因此没有发生之前的关系。答案的其余部分显示了代码比问题中提供的代码更多的情况。
建立同步关系的一件事是加入线程,例如等待前一个线程完成。另一种是启动一个线程,比如前者完成后启动后者线程。
// In a thread
t1.start();
t1.join();
t2.start();
// Or in thread 1
synchronized (O1) {
// actions in thread 1
}
t2.start();
// Or in thread 2
t1.join();
synchronized (O2) {
// actions in thread 2
}
或者,如果后一个线程正在获取前一个线程拥有的外部锁(最终被释放):
// in thread 1
synchronized (outerLock) {
synchronized (O1) {
// actions in thread 1
}
}
// in thread 2
synchronized (outerLock) {
synchronized (O2) {
// actions in thread 2
}
}
或者,如果后一个线程正在等待前一个线程可验证地通知的锁(最终):
boolean done;
// in thread 1
synchronized (O1) {
// actions in thread 1
}
synchronized (commonLock) {
done = true;
commonLock.notify();
}
// in thread 2
synchronized (commonLock) {
while (!done) {
commonLock.wait();
}
}
synchronized (O2) {
// actions in thread 2
}
或者如果后一个线程读取前一个线程写入的 volatile 变量:
volatile boolean done;
// in thread 1
synchronized (O1) {
// actions in thread 1
}
done = true;
// in thread 2
while (!done) {
Thread.yield();
}
synchronized (O2) {
// actions in thread 2
}
在这种特殊情况下,线程 2 仅done
在线程 1 写入后才能确定它是否已读取,done
如果它观察到更改。
实际上,所有这些情况都有同步关系,因此发生在关系之前。同步操作是保证总顺序的操作,因此并非所有的先发生关系都在线程之间。
在Java Language Specification 8th Edition §17中,您可以阅读有关同步操作的信息:
同步顺序是执行的所有同步操作的总顺序。
您可以阅读以下关于发生前关系的内容:
应该注意的是,两个动作之间存在之前发生的关系并不一定意味着它们必须在实现中以该顺序发生。如果重新排序产生与合法执行一致的结果,则不是非法的。
这允许在单个线程中,将非易失性读取重新排序至最近一次获取之后,并且将非易失性写入重新排序至下一个版本之前。
所以,如果你从中取出一些东西: