在Java中避免使用synchronized(this)?
在Java中避免使用synchronized(this)?
每当在SO上出现关于Java同步的问题时,有些人非常渴望指出应该避免使用synchronized(this)
。他们声称,应该优先使用私有引用上的锁。
给出的原因之一是:
- 一些邪恶的代码可能会窃取你的锁(这个非常流行,也有“意外”变体)
- 同一类中的所有同步方法使用完全相同的锁,这会降低吞吐量
- 暴露了过多的信息(不必要)
其他人,包括我,在争论synchronized(this)
是一个很常用(也是Java库中常用)的惯用法,它是安全的,也很容易理解。不应该因为你有一个错误并且不知道在你的多线程程序中正在发生什么而避免它。换句话说:如果适用,就使用它。
我有兴趣看到一些现实世界的例子(不是无聊的东西),其中避免在this
上锁定优于synchronized(this)
。
因此,你是否总是应该避免synchronized(this)
并将其替换为私有引用上的锁?
一些进一步信息(随着回答的更新):
- 我们正在谈论实例同步。
- 考虑了隐式(
synchronized
方法) 和 显式(synchronized(this)
)形式的同步。 - 如果你引用Bloch或其他权威关于此主题的资料,请不要忽略不喜欢的部分(例如在Effective Java中,关于线程安全性的一项通常是在实例本身上锁定,但也有例外部分)。
- 如果您需要比
synchronized(this)
提供的粒度更细的锁定,则synchronized(this)
无法适用,因此这不是问题。
\n\n首先需要指出的是:\n
public void blah() { synchronized (this) { // do stuff } }
\n语义上等同于:\n
public synchronized void blah() { // do stuff }
\n这也是不要使用synchronized(this)
的原因之一。您可能会争辩说,在synchronized(this)
块周围执行其他操作。通常的原因是尝试避免完全执行同步检查,这会导致各种并发问题,具体来说是双重检查锁定问题,这表明使相对简单的检查线程安全变得非常困难。\n私有锁是一种防御机制,从来没有坏处。\n此外,正如你所暗示的,私有锁可以控制粒度。一个对象上的一组操作可能与另一个对象完全不相关,但synchronized(this)
将互斥地排除对所有操作的访问。\nsynchronized(this)
真的什么也没有给你。
我会逐个点进行介绍。
-
一些恶意代码可能会窃取你的锁(这个非常受欢迎,还有一个“意外”的变体)
我更担心的是“意外”的情况。这种使用
this
的方式是你的类的公开接口的一部分,应该予以记录。有时其他代码使用你的锁的能力是必需的。这对于Collections.synchronizedMap
之类的东西是正确的(请参阅javadoc)。 -
同一类中的所有同步方法都使用完全相同的锁,这会降低吞吐量
这种想法过于简单化;只是摆脱
synchronized(this)
不能解决问题。为了增加吞吐量,需要更深入的思考。 -
你暴露了过多的信息(不必要)
这是#1的一个变体。使用
synchronized(this)
是你的接口的一部分。如果你不想/不需要这个暴露出来,就不要这样做。