简体   繁体   English

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

[英]How does the JVM guarantee the visibility of member variable modifications in the referenced object when using synchronized?

I want to know how does the JVM guarantee the visibility of member variable modifications in the referenced object when using synchronized. 我想知道当使用同步时,JVM如何保证引用对象中成员变量修改的可见性。

I know synchronized and volatile will provide visibility for variable modifications. 我知道同步和易失性将为变量修改提供可见性。

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?

Thread A call modify in a sychronized block first, and then pass the object to thread B (Write the reference to a volatile variable.). 线程A的调用首先在sychronized块中进行修改,然后将对象传递给线程B(将引用写入volatile变量。)。 Then thread B call modify again (in synchronized ). 然后线程B再次调用修改(在synchronized )。

Is there any guarantee for a==2? 是否可以保证a == 2? And how is the JVM implemented? JVM如何实现?

Visibility between threads is enforced with Memory Barriers/Fences . 线程之间的可见性由Memory Barriers / Fences强制执行。 In case of synchronized block JVM will insert a memory barrier after the execution of the block completes. 对于synchronized块,JVM将在该块执行完成后插入一个内存屏障。

JVM implements memory barriers with CPU instruction eg a store barrier is done with sfence and load barrier is done with lfence instruction on x86. 例如商店屏障与完成JVM实现具有CPU指令存储器障碍sfence和负载屏障与完成lfence上x86指令。 There is also mfence and possibly other instructions which can be specific to CPU architecture. 还有mfence以及可能其他特定于CPU体系结构的指令。

For your (still incomplete!) example, if we can assume the following: 对于您的示例(仍不完整!),如果我们可以假设以下内容:

  1. The code in thread A initializing test is guaranteed to run before thread B uses it. 保证线程A初始化test的代码可以在线程B使用它之前运行。
  2. The locker variable contains a reference to the same object for threads A & B. locker变量包含对线程A和B的同一对象的引用。

then we can prove that a == 2 will be true at the point you indicate. 那么我们可以证明a == 2在您指示的点上为真。 If precondition 1 is not guaranteed, then thread B may get an NPE. 如果不能保证前提条件1,则线程B可能会获得NPE。 If precondition 2 is not guaranteed (ie threads A and B may synchronize on different objects) then there is not a proper happens-before relationship to ensure that thread B sees the result of thread A's actions on a . 如果不能保证前提条件2(即线程A和B 可以在不同的对象上同步),那么就没有适当的先发生后关系来确保线程B看到线程A对a操作的结果。

(@NathanHughes commented that the volatile is unnecessary. I wouldn't necessarily agree with that. It depends on details of your example that you still haven't show us.) (@NathanHughes评论说, volatile是不必要的。我不一定会同意。这取决于您的示例详细信息,但您仍未向我们展示。)


How JVM implements it? JVM如何实现它?

The actual implementation is Java platform and (in theory) version specific. 实际的实现是Java平台和(理论上)版本特定的。 The JVM spec Memory Model places constraints on how a program that obeys "the rules" will behave. JVM规范“内存模型”对遵守“规则”的程序的行为方式设置了约束。 It is entirely implementation specific how that actually happens. 实际情况完全取决于实现方式。

I know the memory barrier, does it flush all cache to main storage? 我知道内存障碍,它会将所有缓存刷新到主存储吗?

That is implementation specific too. 那也是特定于实现的。 There are different kinds of memory barrier that work in different ways. 有不同种类的内存屏障以不同的方式起作用。 The JIT compiler will emit native code that uses the appropriate instructions to meet the guarantees required by the JLS. JIT编译器将发出使用适当的指令来满足JLS要求的本机代码。 If there is a way to do this without doing a full cache flush then the implementation may do that. 如果有一种方法可以执行此操作而不执行完整的缓存刷新,则实现可以这样做。

(There is a JVM command line option to tell the JIT compiler to output the native code. If you really want to know what is happening under the hood, that is a good place to start looking.) (有一个JVM命令行选项,告诉JIT编译器输出本机代码。如果您真的想知道幕后发生的事情,那么这是开始查找的好地方。)

But if you are trying to understand / analyze your application's thread-safety, you should be doing it in terms of the Java Memory Model. 但是,如果您试图了解/分析应用程序的线程安全性,则应该按照Java内存模型来进行。 Also, use higher level concurrency abstractions that allow you to avoid the lower level pitfalls. 另外,使用更高级别的并发抽象,可以避免出现更低级别的陷阱。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 JVM 是否保证缓存非 volatile 变量? - Does JVM guarantee to cache not volatile variable? Java 是否还保证同步之前的所有变量更改对于在同一对象上同步的下一个线程都是可见的? - Does Java also guarantee that all variable changes before synchronized will be visible to the next thread which synchronizes on same object? JVM 如何保证 finally 块的执行? - How does the JVM guarantee execution of the finally block? 如何保证对对象的所有非线程安全引用都将被同步? - How to guarantee that all non-thread-safe references to an object will be synchronized? JVM是否为每个对象创建一个互斥锁以实现'synchronized'关键字?如果没有,怎么样? - Does the JVM create a mutex for every object in order to implement the 'synchronized' keyword? If not, how? 在同步块中使用wait()方法时,JVM是否在等待notify()时释放监视器? - When using wait() method in a synchronized block does JVM release the monitor while waiting for notify()? 在调用“notify”时,Java JVM是否会保证正确的“等待”? - Does the Java JVM guarantee the correct “wait” will be notified when calling “notify”? 如何正确使用同步块或锁来保证变量的可见性? - How to properly use synchronized block or locks to ensure variable visibility? 同步保证线程是否会看到另一个线程修改的非易失性变量的最新值? - Does synchronized guarantee a thread will see the latest value of a non-volatile variable being modified by another thread? 将不相关类的成员用作锁定对象时,同步块不起作用? - Synchronized blocks don't work when using member of unrelated class as lock object?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM