Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 字段读取同步和易失性同步之间的可见性差异_Java_Multithreading_Synchronization_Volatile_Thread Synchronization - Fatal编程技术网

Java 字段读取同步和易失性同步之间的可见性差异

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) { }

我已经读了下面这篇文章

提问者写道

同步的要点是确保 此线程读取的帐户余额是当前的,并且 对acct.balance中对象字段的挂起写入也会被删除 写入主存储器。

最流行的答案是:

你说得对

请研究此代码:

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 ");
    }

}
在我的电脑上,此程序不会终止

因此我认为

  • 若我更改volatile变量,我将在另一个线程中看到实际值 对于任何优秀的地方
  • 如果我改变了监视器“A”中同步部分的变量,我会 仅在监视器“A”的同步部分中查看实际值(例如,在另一个线程中)
  • 我说得对吗

  • 是的,这是正确的,因为易失性写入发生在从变量读取写入值之前
  • 不完全是。可以保证同一监视器上的另一个线程
    synchronized
    将看到更新的值,因为监视器释放发生在同一监视器被另一个线程获取之前。如果不获取相同的监视器,其他线程可能会看到更新的值。你公式中的“唯一”太强了:)
  • (你说得对)

    内存模型如下所述:

    它特别指出:

    监视器上的解锁发生在该监视器上的每个后续锁定之前 监视器

    对易失性字段的写入(§8.3.1.4)发生在每次后续操作之前 读一下这个领域

    因此,只有同一个监视器上的锁和解锁会按照您的意愿进行操作,也包括易变变量的所有写入和读取。因此,您的程序可能不会终止,因为您在读取时未锁定所述监视器,并且没有发生在关系之前

    需要注意的一件事(这就是多线程bug如此烦人的原因):

    您可能会在其他线程中看到更改。也许不是。在大多数架构上,您可能会在正常处理期间看到它,并且可能会在高负载期间出现错误,这使得它很难重现。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缓存的信息