class A {
private int number;
public void a() {
number = 5;
}
public void b() {
while(number == 0) {
// ...
}
}
}
如果调用方法b,然后启动一个新线程并触发方法a,则不能保证方法b会看到number
的更改,因此b
可能永远不会终止。
当然,我们可以使number
成为volatile
以解决这个问题。但是出于学术原因,让我们假设volatile
不是一个选项:
JSR-133 FAQs告诉我们:
当我们退出同步块时,我们释放监视器,这会刷新缓存到主内存中,以便其他线程可以看到该线程所做的写操作。在我们进入同步块之前,我们获取监视器,这会使本地处理器缓存无效,以便变量将从主内存中重新加载。
这听起来就像我只需要让a
和b
进入和退出任何synchronized
-Block,无论它们使用什么监视器。更确切地说,它听起来像是这样...:
class A {
private int number;
public void a() {
number = 5;
synchronized(new Object()) {}
}
public void b() {
while(number == 0) {
// ...
synchronized(new Object()) {}
}
}
}
这段内容的翻译如下:
...将消除该问题,确保 b
看到对 a
的更改,并最终终止。
然而,常见问题解答也明确说明:
Another implication is that the following pattern, which some people use to force a memory barrier, doesn't work:
synchronized (new Object()) {}
This is actually a no-op, and your compiler can remove it entirely, because the compiler knows that no other thread will synchronize on the same monitor. You have to set up a happens-before relationship for one thread to see the results of another.
现在这很令人困惑。我以为同步语句会导致缓存刷新。它肯定不能以一种只有在同步于相同监视器的线程才能看到主内存中更改的方式刷新缓存,特别是对于基本上做同样事情的volatile,我们甚至不需要监视器,或者我错了吗?那么为什么这是一个无操作,并且不会通过保证使b
终止?