Java 字段读取同步和易失性同步之间的可见性差异
我已经读了下面这篇文章 提问者写道 同步的要点是确保 此线程读取的帐户余额是当前的,并且 对acct.balance中对象字段的挂起写入也会被删除 写入主存储器。 最流行的答案是: 你说得对 请研究此代码:Java 字段读取同步和易失性同步之间的可见性差异,java,multithreading,synchronization,volatile,thread-synchronization,Java,Multithreading,Synchronization,Volatile,Thread Synchronization,我已经读了下面这篇文章 提问者写道 同步的要点是确保 此线程读取的帐户余额是当前的,并且 对acct.balance中对象字段的挂起写入也会被删除 写入主存储器。 最流行的答案是: 你说得对 请研究此代码: public class VolatileTest { static/* volatile */boolean done = false; public VolatileTest() { synchronized (this) { }
public class VolatileTest {
static/* volatile */boolean done = false;
public VolatileTest() {
synchronized (this) {
}
}
public static void main(String[] args) throws Exception {
Runnable waiter = new Runnable() {
public void run() {
while (!done)
;
System.out.println("Exited loop");
}
};
new Thread(waiter).start();
Thread.sleep(100); // wait for JIT compilation
synchronized (VolatileTest.class) {
done = true;
}
System.out.println("done is true ");
}
}
在我的电脑上,此程序不会终止
因此我认为
synchronized
将看到更新的值,因为监视器释放发生在同一监视器被另一个线程获取之前。如果不获取相同的监视器,其他线程可能会看到更新的值。你公式中的“唯一”太强了:)您可能会在其他线程中看到更改。也许不是。在大多数架构上,您可能会在正常处理期间看到它,并且可能会在高负载期间出现错误,这使得它很难重现。JVM不提供任何保证,如果之前没有发生任何情况(即,易失性、同步、在同一线程中或在链接中的其他情况),JVM将在什么时候看到它,但会尽力平稳运行。但是,即使没有监视器,线程最终也会看到更新的值吗?即使在这种情况下,内存在一段时间内不一致,循环不应该在一段时间后检测到翻转的布尔吗?@monocell这可能发生,也不可能发生-我们无法保证何时会发生,以及是否会发生。我不知道,我认为任何转换都可以通过对语句效果的重新排序来解释,而不是完全没有效果。想想人们付钱给我写java代码:(@Alexey,我同意这个答案-Core i7没有顺序和一般的重新排序(而且总是这样)。我会很惊讶他们不赞成在高性能芯片中使用这样一种主要的加速技术。@monocell由于多线程而导致的不终止的情况在这里被简单地提到了。事实上,整个事情都是非常数学化的,很难理解。这种特殊情况是由于“此外,如果一个动作y在O中,并且hb(x,y)或so(x,y),那么x在O中”,这表示-除非存在死锁(或其他类型的锁),如果存在HB关系-您最终将看到变量更改。但是,这并没有指定没有HB时会发生什么。事实上,它甚至将挂起定义为允许挂起,以防线程中没有可能阻止挂起的操作。术语“主内存”"在这里是一个松散的术语。它只表示一致的视图。二级缓存相互通信以实现这一点,因此更改甚至可能不在三级缓存中,更不用说主内存了。@Peter Lawrey我对CPU的知识还不够。我不懂任何关于缓存如何保持同步的内容。通常缓存会相互通信,而不是绕过g主存,因为缓存速度更快,这将告诉你更多关于CPU缓存的信息