让线程X
中构造非线程安全的可变对象A
。 A
将构建后的X
传递给线程B
。 B
变异X
而A
永远不会再次访问X
。
X
是否始终能够正确显示B
的状态?
X
是否有效地限制线程?
我对 Java Concurrency in Practice 的阅读似乎表明X
未正确发布但我不能在运行数百万的测试装备中导致线程B
出现任何问题重复。我怀疑这只是运气不好。
对于背景,X
代表了许多复杂的类,我无法控制这些类是由仅具有Java基础知识的建模者创作的。强烈优选X
没有同步块或其他并发机制或要求。
我目前正在通过让线程A
为X
B
调用X
的线程安全工厂来解决此问题,从而使MATCH (:SomeLabel{someProperty:false})-[*..999999]->(x)
WITH distinct x
SET x.someProperty = false
线程受限制。
答案 0 :(得分:0)
仅对最终字段安全发布
Java内存模型并不能保证对象X
将完全发布(完全构造)到线程A
。
要确保这一点,您需要使其成为不可变的(所有成员字段为final)或同步。
引用JSR-133
:
最终字段的语义已得到加强,以实现线程安全的不可变性 没有明确的同步。这可能需要诸如商店门槛等步骤 设置最终字段的构造函数的结尾。
只有你需要避免的是在构造函数完成之前将字段泄漏出类。
<强>测试强>
jcstress
实际上是一个展示出版期间赛车后果的示例项目:JMMSample_06_Finals.java
请注意,必须采取一些措施来复制问题,例如使用许多字段。 JMM的实现自然取决于您使用的特定JRE,并且使用的内存屏障的影响取决于所使用的硬件。
在使用Oracle JDK 8的硬件上,我无法使用带有jcstress
的示例重现不安全的出版物。
<强>同步强>
有一个&#34;发生在之前&#34;所有同步动作之间的关系。这称为同步顺序。基本上,当您使用任何同步机制时,您可以保证之前的操作在其之后可见。
正如Java Language Specification中所述:
如果程序正确同步,则程序的所有执行都将显示为顺序一致
在实践中
在实践中,由于使用该对象的线程无法看到构造函数中的操作,因此很难遇到问题。 主要原因是使用同步机制。您可以检查一些确保javadoc中之前发生关系的操作:Memory Visibility
正如我在jcstress
样本中提到的那样,JRE现在似乎非常善于确保一致的结果,即使它根据语言规范不需要。