【发布时间】:2010-10-01 08:24:44
【问题描述】:
每当 SO 上出现关于 Java 同步的问题时,有些人非常急切地指出应该避免使用 synchronized(this)。相反,他们声称,锁定私有引用是首选。
一些给定的原因是:
- some evil code may steal your lock(这个很受欢迎,还有一个“意外”变种)
- all synchronized methods within the same class use the exact same lock, which reduces throughput
- you are (unnecessarily) exposing too much information
包括我在内的其他人认为synchronized(this) 是一个经常使用的习语(也在Java 库中),安全且易于理解。它不应该被避免,因为你有一个错误并且你不知道你的多线程程序中发生了什么。换句话说:如果它适用,那么就使用它。
我有兴趣看到一些真实的例子(没有 foobar 的东西),当 synchronized(this) 也可以完成这项工作时,避免锁定 this 是更可取的。
因此:您是否应该始终避免使用synchronized(this) 并将其替换为对私有引用的锁定?
一些进一步的信息(在给出答案时更新):
- 我们正在讨论实例同步
- 隐式(
synchronized方法)和显式形式的synchronized(this)都被考虑 - 如果您引用 Bloch 或其他有关该主题的权威,请不要忽略您不喜欢的部分(例如 Effective Java,线程安全项目:通常它是实例本身的锁,但是有例外。)
- 如果您需要除
synchronized(this)之外的锁定粒度,那么synchronized(this)不适用,所以这不是问题
【问题讨论】:
-
我还想指出上下文很重要 - “通常它是实例本身的锁定”位在有关记录条件线程安全类的部分中,当你'重新公开锁。换句话说,这句话适用于您已经做出此决定的情况。
-
在没有内部同步的情况下,当需要外部同步时,锁往往是实例本身,Bloch 基本上是这样说的。那么,为什么在“this”上锁定的内部同步也不是这种情况呢? (文档的重要性是另一个问题。)
-
在扩展粒度和额外的 CPU 缓存和总线请求开销之间进行权衡,因为锁定外部对象很可能需要在 CPU 缓存之间修改和交换单独的缓存行(参见 MESIF和 MOESI)。
-
我认为,在防御性编程的世界中,您不是通过成语而是通过代码来防止错误。当有人问我“您的同步优化程度如何?”时,我想说“非常”而不是“非常”,除非其他人不遵循这个习惯用法。
标签: java multithreading synchronization synchronized