【问题标题】:Does a volatile reference really guarantee that the inner state of the object is visible to other threads?volatile 引用真的保证对象的内部状态对其他线程可见吗?
【发布时间】:2016-03-24 13:03:34
【问题描述】:

在阅读“Java 并发实践”时,我遇到了以下问题 -

为了安全地发布对象,对象的引用和对象的状态必须同时对其他线程可见。正确构造的对象可以通过以下方式安全发布:

  • 从静态初始化器初始化对象引用;
  • 将对其的引用存储到 volatile 字段或 AtomicReference 中;
  • 将对它的引用存储到正确构造的对象的最终字段中;或
  • 将对它的引用存储到由锁适当保护的字段中。

我的问题是 - 第二点是真的吗? IE。我可以通过将对象的引用存储在易失性引用中来使其他线程可以看到对象的状态吗?如果不是,我是不是看错了以上几点?

【问题讨论】:

  • 您了解“安全发布”在这种情况下的含义吗?
  • 在我看来(很高兴得到纠正)这意味着阅读线程应该能够看到该对象成员的正确值(正确值 - 分配给该对象的构造函数)
  • 是的,这是真的。易失性写入与任何后续易失性读取(相同变量)创建发生前的关系。在单个线程中还有一个happens-before关系。再加上 h-b 是可传递的,这意味着写入线程在存储 volatile 引用之前所做的任何事情都将对任何其他已读取 volatile 引用的线程可见。顺便说一句,任何对象的任何字段都是如此,因此您可以在任何地方进行五次非易失性写入,然后是易失性“保护”写入。
  • @AshutoshAgrawal 否。读取线程在读取 volatile 引用后,无法看到在 volatile 写入之前发生的写入尚未发生的状态。这就是为什么happens-before是传递性的很重要的原因。

标签: java multithreading memory-visibility


【解决方案1】:

使对象易失不会使他的状态发布到所有线程,即

volatile A a = new A();
private static class A {
    int i = 0;
    int j = 0;
    int k = 0;
}

不一样

A a = new A();
private static class A {
    volatile int i = 0;
    volatile int j = 0;
    volatile int k = 0;
}

(1) 使您的引用变得易变,即如果一个线程重新分配引用,则此重新分配将立即“发布”给其他线程

【讨论】:

  • 感谢您的回答!显然,即使只是参考是易变的,也足够了。读取引用的任何线程还将看到在设置 volatile 引用本身之前完成的任何写入(假设其他写入由设置了 volatile 引用的同一线程完成)
猜你喜欢
  • 2012-08-10
  • 2011-01-29
  • 2017-03-18
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多