避免在Java中同步(this)?

每当SO上出现有关Java同步的问题时,有些人都非常渴望指出应该避免。相反,他们声称,对私有引用的锁定是首选。synchronized(this)

一些给定的原因是:

包括我在内的其他人认为,这是一个经常被使用的成语(也在Java库中),是安全的,并且很好理解。不应该避免它,因为你有一个错误,你不知道你的多线程程序中发生了什么。换句话说:如果它适用,那就使用它。synchronized(this)

我有兴趣看到一些现实世界的例子(没有foobar的东西),其中避免锁定是可取的,当也可以做这项工作时。thissynchronized(this)

因此:您是否应该始终避免同步(this)并将其替换为私有引用上的锁定?


一些进一步的信息(随着答案的给出而更新):

  • 我们正在谈论实例同步
  • 同时考虑隐式 (方法) 和显式形式synchronizedsynchronized(this)
  • 如果你引用布洛赫或其他权威人士的话,不要遗漏你不喜欢的部分(例如,有效的Java,线程安全上的项目:通常是实例本身的锁,但也有例外
  • 如果您需要除提供以外的锁定粒度,则不适用,因此这不是问题所在synchronized(this)synchronized(this)

答案 1

我将分别介绍每个要点。

  1. 一些邪恶的代码可能会偷走你的锁(这个非常受欢迎,也有一个“意外”的变体)

    我更担心的是意外。它相当于是类的公开接口的一部分,应该记录下来。有时需要其他代码使用您的锁的能力。对于类似的东西来说也是如此(参见javadoc)。thisCollections.synchronizedMap

  2. 同一类中的所有同步方法都使用完全相同的锁,这会降低吞吐量

    这是过于简单化的想法;只是摆脱并不能解决问题。正确的吞吐量同步需要更多考虑。synchronized(this)

  3. 您(不必要地)暴露了太多信息

    这是 #1 的变体。使用是界面的一部分。如果你不想/不需要这个暴露,不要这样做。synchronized(this)


答案 2

好吧,首先应该指出的是:

public void blah() {
  synchronized (this) {
    // do stuff
  }
}

在语义上等效于:

public synchronized void blah() {
  // do stuff
}

这是不使用 的一个原因。你可能会争辩说,你可以在街区周围做一些事情。通常的原因是尽量避免必须进行同步检查,这会导致各种并发问题,特别是双重检查锁定问题,这恰恰表明制作相对简单的检查线程安全是多么困难。synchronized(this)synchronized(this)

私人锁是一种防御机制,这绝不是一个坏主意。

此外,正如您所提到的,私有锁可以控制粒度。对一个对象的一组操作可能与另一组操作完全无关,但会相互排除对所有操作的访问。synchronized(this)

synchronized(this)只是真的没有给你任何东西。