首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JVM如何保证在使用同步时,成员变量修改在引用对象中的可见性?

JVM如何保证在使用同步时,成员变量修改在引用对象中的可见性?
EN

Stack Overflow用户
提问于 2019-04-18 14:32:40
回答 2查看 89关注 0票数 1

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

我知道同步和易失性将为变量修改提供可见性。

代码语言:javascript
复制
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再次调用修改(在synchronized中)。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-19 03:37:04

为了你(还不完整!)例如,如果我们可以假设如下:

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

然后,我们可以证明,在您指出的点上,a == 2是正确的。如果不保证前提条件1,则线程B可以得到NPE。如果不能保证先决条件2(即线程A和B可以在不同的对象上同步),那么就没有适当的发生--在确保线程B在a上看到线程A的操作结果之前。

(@NathanHughes评论说,volatile是不必要的。我不一定同意这一点。这取决于你的例子的细节,你还没有向我们展示。)

JVM是如何实现它的?

实际的实现是Java平台,(理论上)是特定于版本的。JVM规范内存模型对遵守“规则”的程序的行为设置了约束。这完全是具体的实现,具体是如何发生的。

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

这也是具体的实现。有不同类型的记忆障碍,以不同的方式工作。JIT编译器将发出本机代码,这些代码使用适当的指令来满足JLS所要求的保证。如果有一种方法可以在不进行完全缓存刷新的情况下完成这一操作,那么实现可能会这样做。

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

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

票数 2
EN

Stack Overflow用户

发布于 2019-04-18 15:11:40

线程之间的可见性由记忆屏障/栅栏强制执行。如果是synchronized块,JVM将在块执行完成后插入一个内存屏障。

JVM用CPU指令实现内存屏障,例如,用sfence来设置存储屏障,在x86上使用lfence指令来设置加载屏障。还有mfence,可能还有其他指令,可以是特定于CPU体系结构的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55748270

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档