没有发生之前的安全发布?无论如何除了决赛?
Posted
技术标签:
【中文标题】没有发生之前的安全发布?无论如何除了决赛?【英文标题】:Safe Publication without happens-before? Anyhow besides final? 【发布时间】:2011-07-24 10:48:53 【问题描述】:根据 JCP(16.2.2. 安全发布):
这种事前发生的保证实际上是比安全发布更强大的可见性和排序承诺。当 X 从 A 安全地发布到 B 时,安全发布保证了 X 的状态的可见性,但不能保证 A 可能触及的其他变量的状态。但是,如果 A 将 X 放入队列中发生——在 B 从该队列中取出 X 之前,B 不仅看到 X 处于 A 离开它的状态(假设 X 没有随后被 A 或其他任何人修改),而且 B 看到A 在交接前所做的一切(同样,受到同样的警告)
我想知道什么时候安全发布可以没有发生之前,即不使用 volatile/atomics 或同步(或通过使用其中列出的任何一个的 AQS 等框架)?
一种情况是不可变对象中的最终字段,您可以在其中按原样发布它而无需任何额外步骤。
还有其他情况吗?
UPD:重新阅读 3.5.3。 Safe Publication Idioms,另一种情况 - “从静态初始化程序初始化对象引用”。现在看来这些都是选项。
【问题讨论】:
您有引用链接吗?它不在current JLS (third edition) 中。 来自《Java 并发实践》一书 啊,谢谢。从首字母缩略词 JCP 中,我首先想到了 Java Community Process,它没有这样的数字。 【参考方案1】:我不知道除了final
之外的任何东西,而看看http://java.sun.com/docs/books/jls/third_edition/html/memory.html 似乎证实了这一点。第 17.4 章涉及除 final
之外的所有内容,这将在 17.5 中单独解释。
但应该注意的是,JVM 内部的任何内容都必须始终可见,然后才可能导致 Java 代码中的数据竞争。这主要影响数组长度、虚拟表指针和字符串内容。这些永远不会被视为未初始化或不一致。
【讨论】:
【参考方案2】:您可能在 Java In Concurrency 中找到的所有案例列表:
为了安全地发布对象, 引用对象和 对象的状态必须对 其他线程同时进行。一种 正确构造的对象可以是 安全发布者:
初始化一个对象引用 静态初始化器;
将对它的引用存储到 volatile 字段或 AtomicReference;
将对它的引用存储到final中 正确构造的领域 目的;或
将引用存储到字段中 由锁妥善保护。
【讨论】:
【参考方案3】:静态初始化在synchronized(class)
内部完成,所以非常强大。
虽然final
语义较弱,但我怀疑实现是否真的那么弱。
Doug Lea 提出了更原始的栅栏的建议,http://cs.oswego.edu/pipermail/concurrency-interest/2009-January/005743.html
【讨论】:
以上是关于没有发生之前的安全发布?无论如何除了决赛?的主要内容,如果未能解决你的问题,请参考以下文章
Linux下超简单的Mysql自动备份+定期删除之前备份文件脚本