在Java中,什么时候可以逃脱"没有对多个并发线程的读/写变量使用synchronized?
我读到了一些令人惊讶的并发错误:double-checked-locking和hash-maps,并且在共享读/写情况下默认情况下一直使用同步,但是,我开始想知道它何时会出现问题。没关系。
例如,我可以使用哪种通用规则来确定实际何时可以安全地从这样的方法中省略synchronized
:
T getFoo() {
if (this.foo == null) {
this.foo = createFoo() // createFoo is always thread safe.
}
return this.foo;
}
其中:
T
可能是基元或任意对象createFoo
始终是线程安全的,可以多次调用,但未指定。getFoo()
可以"最终一致"。如果T是像int
这样的原语吗?那么Integer
呢?像String这样的简单对象呢?等
答案 0 :(得分:2)
什么时候不同步读/写变量是安全的?
只有当您完全理解对底层硬件,JVM和应用程序的影响时,才会回答。如果可能的话,我仍然会推荐这种方法,从很多阅读和实验开始。
在实践中,您应该能够使用一些常用模式来最小化代码中synchronized
方法或块的数量,而无需了解所述模式的所有复杂性。这不应该增加你的应用程序的风险,因为即使围绕synchronized
的使用,也有非平凡的细节,如果你理解了所有这些细节,你会问一个不同的问题。
尽管如此,您的里程可能会有所不同,特别是如果您所使用的常用模式的形式和实现没有得到您当地的并发大师的祝福。
足够的诽谤,给我一些例子
java.util.concurrent
。volatile
volatile
变量查看http://www.ibm.com/developerworks/library/j-jtp06197/的常见模式。答案 1 :(得分:1)
在没有内存障碍的线程之间共享数据永远不会安全。
getFoo()
的正确性取决于foo
字段的声明。
如果多个线程调用getFoo()
,则每个线程最终可能会使用T
的不同实例。如果没有内存障碍,一个线程的操作(比如分配给字段foo
)可能永远不会被其他线程看到 - 永远!换句话说,如果没有同步,则不保证一致性,“最终”或其他方式。
如果foo
为volatile
,则会充当内存屏障,然后您就会遇到多个线程在短时间内获得不同T
的问题。他们竞相创造实例。