在Java中对volatile对象进行非易失性引用的行为

时间:2018-01-19 07:58:55

标签: java multithreading concurrency thread-safety volatile

来自C / C ++,我对Java中的volatile对象行为有点困惑。

我知道Java中的volatile有两个属性:

  1. 不要将对象带入缓存,始终将其保存在主内存中。
  2. 保证"发生之前"
  3. 但是我不确定如果我对对象进行新的非易失性引用会发生什么。例如,

    class Example {
       private volatile Book b = null;
    
       public init() { b = new Book(...); }
    
       public use() {
         Book local = b;
         local.read();
       }
    }
    

    AFAIK,volatile意味着"书籍对象" b引用的应该在主内存中。编译器可能在内部实现引用作为指针,因此b指针可能位于缓存中。根据我的理解,volatile是对象的限定符,而不是引用/指针。

    问题是:在use方法中,本地引用不是volatile。这个"本地"引用将基础Book对象从主内存带入缓存,实质上使对象不是" volatile"?

2 个答案:

答案 0 :(得分:4)

没有“易变物”这样的东西,也没有“永远保存在主存中”的保证。

引用类型保证的所有volatile变量都是在对该变量的写入与后续读取同一变量之间存在发生之前的关系。 / p>

由于发生 - 之前关系是可传递的,它们适用于您的示例代码,即对b = new Book(...)所有对Book实例所做的修改都是在写入引用之前提交的到b因此Book local = b; local.read(); read()保证在编写引用之前看到其他线程所做的所有修改。

这并不意味着Book实例的内存是特殊的。例如。在引用已写入b之后对实例所做的修改可能对其他线程可见或可能不可见,而其他线程可能只感知其中一些或看到它们就好像是在不同的顺序。

因此,获取对象引用的方式无关紧要,重要的是是在通过b发布对该对象的引用之前还是之后进行更改。同样,只要在通过阅读b获取引用后执行此操作,无论您如何执行对象的读取访问都无关紧要。

使用local.read();您通过本地变量local访问该对象,并且在read()内,this将访问相同的引用,但重要的是在阅读对象的状态之前,您已通过阅读b获取了参考。

答案 1 :(得分:2)

volatile是关于引用,而不是对象。

它保证在另一个线程设置值b之后读取变量b的任何线程将获得由另一个线程分配给b的值,而不是某些缓存值