【问题标题】:How does the JVM guarantee the visibility of member variable modifications in the referenced object when using synchronized?JVM在使用synchronized时如何保证被引用对象中成员变量修改的可见性?
【发布时间】:2019-04-19 16:09:11
【问题描述】:

想知道JVM在使用synchronized时如何保证被引用对象中成员变量修改的可见性。

我知道 synchronized 和 volatile 将为变量修改提供可见性。

class Test{
    public int a=0;

    public void modify(){
        a+=1;
    }
}


//Example:

// Thread A:
 volatile Test test=new Test();
 synchronized(locker){
   test.modify();
 }

// then thread B:
synchronized(locker){
   test.modify();
}

// Now, I think test.a==2 is true. Is it ok? How JVM implements it?
// I know the memory barrier, does it flush all cache to main storage?

线程 A 调用首先在 sychronized 块中进行修改,然后将对象传递给线程 B(写入对 volatile 变量的引用。)。 然后线程 B 再次调用 modify(在synchronized)。

a==2 有什么保证吗? JVM是如何实现的?

【问题讨论】:

  • 您的示例代码与您描述的场景不匹配,并且不完整,请更新您的问题,以便我们确定我们理解您的真正要求。
  • @StephenC 好的,我编辑这段代码。
  • 是的,在 A 和 B 运行之后,a 将等于 2。而且这里不需要 volatile。
  • 这仍然不是一个完整的例子。提示:如果我不能将它复制到文件中,编译并运行它,它是不完整的。在这种情况下,仍然缺少重要的细节。 (@NathanHughes 做了一些假设……)
  • @Stephen C 好的,我会尽快编辑它

标签: java jvm


【解决方案1】:

线程之间的可见性通过Memory Barriers/Fences 强制执行。如果是synchronized 块,JVM 会在块执行完成后插入内存屏障。

JVM 使用 CPU 指令实现内存屏障,例如存储屏障使用 sfence 完成,加载屏障使用 x86 上的 lfence 指令完成。还有mfence 和可能特定于 CPU 架构的其他指令。

【讨论】:

    【解决方案2】:

    对于您的(仍然不完整!)示例,如果我们可以假设以下内容:

    1. 线程 A 中初始化 test 的代码保证在线程 B 使用它之前运行。
    2. locker 变量包含对线程 A 和 B 的同一对象的引用。

    那么我们可以证明a == 2 在您指定的那一点上是正确的。如果不保证前提条件 1,则线程 B 可能会获得 NPE。如果不保证前提条件 2(即线程 A 和 B 可能在不同的对象上同步),则没有适当的发生前关系来确保线程 B 看到线程 A 对 @987654324 的操作的结果@。

    (@NathanHughes 评论说volatile 是不必要的。我不一定同意这一点。这取决于您尚未向我们展示的示例细节。)


    JVM是如何实现的?

    实际实现是 Java 平台和(理论上)版本特定的。 JVM 规范内存模型对遵守“规则”的程序的行为方式进行了限制。这完全取决于具体的实现方式。

    我知道内存屏障,它会将所有缓存刷新到主存储吗?

    这也是特定于实现的。有不同种类的内存屏障以不同的方式工作。 JIT 编译器将发出使用适当指令的本机代码,以满足 JLS 要求的保证。如果有办法做到这一点 不进行完全缓存刷新,那么实现可以 这样做。

    (有一个 JVM 命令行选项可以告诉 JIT 编译器输出本机代码。如果你真的想知道幕后发生了什么,这是一个开始寻找的好地方。)

    但如果您试图理解/分析应用程序的线程安全性,您应该根据 Java 内存模型来进行。此外,请使用更高级别的并发抽象来避免较低级别的陷阱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-28
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      • 1970-01-01
      相关资源
      最近更新 更多