【问题标题】:Non volatile head and tail reference in Java LinkedBlockingQueueJava LinkedBlockingQueue 中的非易失性头尾引用
【发布时间】:2017-02-18 23:41:25
【问题描述】:

为什么java.util.concurrent.LinkedBlockingQueueheadtail 引用不是volatile

一个线程中headtail 的任何更改可能对另一个线程不可见,那么这会导致问题吗?

【问题讨论】:

  • 有趣的问题。尤其是当人们开始阅读该类的源代码并发现它包含一些关于锁定的注释掉的内容时;和锁定方法......没有使用?!
  • 它使用锁来提供线程安全。
  • 从源码看,head 和 tail 是“transient”,不同于“non-volatile”。
  • transientvolatile 不相关。 transient 用于序列化。
  • @JohnVint 是的,虽然它们的意思相同(两个词都是同义词,意思是“只持续很短的时间”),但它们没有任何关系。

标签: java concurrency


【解决方案1】:

headtail 将由 putLocktakeLock 保护。只要您正确同步,您就不需要将字段声明为volatile

所以,回答你的问题。如果它们正确同步(它们是),则这些字段不需要是volatile

如果您发现有部分代码可疑,请告诉我,否则我找不到任何理由让它们变得易变。

【讨论】:

  • 您的意思是 ReentrantLock 保证所有后续的读取和写入都将发生在主内存中,而不是像同步块中那样缓存,因此另一个线程调用 take 方法将始终从主内存中读取头部。
  • 是的,完全正确。来自 JDK All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in section 17.4 of The Java™ Language Specification
【解决方案2】:

简短回答:不,它不会导致可见性问题。

长答案:它是阻塞的,即它在实现时有某种synchronized {} 阻塞。您可以通过synchronized {} 块传播变量更改。

【讨论】:

    【解决方案3】:

    java.util.concurrent.LinkedBlockingQueue 有头有尾 引用为非易失性

    首先,volatile 是一种同步技术,但不是唯一的技术 - 其他同步技术是显式锁定,因此 volatile 并不总是强制性的,前提是字段同步是通过锁定处理的。因此,正如 John Vint 的回答中所解释的,这里使用了这两个锁。

    其次,您通常不会看到 volatile 被用于引用类型。它通常用于原始类型,请参阅此another SO question 以获得更多解释 - 那里的两个答案都很好。

    另外refer this question 看到仅将引用类型声明为volatile 有时是不够的,并且仍然会产生不正确的结果,因为通常对引用类型重要的是引用类型字段的非陈旧值而不是实际引用本身。对所有线程正确可见的非陈旧引用可能具有不同线程中基础对象的陈旧字段值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多