为什么 'synchronized (new Object()) {}' 是 no-op?
在下面的代码中:
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 常见问题解答告诉我们:
退出同步块后,我们释放监视器,其效果是将缓存刷新到主内存,以便此线程进行的写入可以对其他线程可见。在我们可以进入同步块之前,我们获取监视器,其效果是使本地处理器缓存无效,以便从主内存中重新加载变量。
这听起来好像我只需要两者,就可以进入和退出任何-Block,无论他们使用什么显示器。更准确地说,它听起来像这样...:a
b
synchronized
class A {
private int number;
public void a() {
number = 5;
synchronized(new Object()) {}
}
public void b() {
while(number == 0) {
// ...
synchronized(new Object()) {}
}
}
}
...将消除问题,并将保证将看到更改,因此最终也将终止。b
a
然而,常见问题解答也明确指出:
另一个含义是,以下模式(有些人用来强制设置内存屏障)不起作用:
synchronized (new Object()) {}
这实际上是一个 no-op,编译器可以完全删除它,因为编译器知道没有其他线程将在同一监视器上同步。您必须为一个线程设置“发生前”关系才能看到另一个线程的结果。
现在这令人困惑。我以为同步语句会导致缓存刷新。它肯定不能将缓存刷新到主内存,因为主内存中的更改只能由在同一监视器上同步的线程看到,特别是因为对于基本上执行相同操作的易失性,我们甚至不需要监视器,或者我在那里错了吗?那么,为什么这是一个禁止操作并且不会导致保证终止呢?b