在 Java 中避免同步(this)?

Avoid synchronized(this) in Java?(在 Java 中避免同步(this)?)

本文介绍了在 Java 中避免同步(this)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每当 SO 上出现关于 Java 同步的问题时,有些人非常急切地指出应该避免使用 synchronized(this).相反,他们声称,最好锁定私有引用.

一些给定的原因是:

  • 一些恶意代码 可能会偷走你的锁(这个很受欢迎,也有一个意外"变体)
  • 同一类中的所有同步方法使用完全相同锁,会降低吞吐量
  • 你也(不必要地)暴露了很多信息

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

我有兴趣看到一些真实世界的示例(没有 foobar 的东西),当 synchronized(this) 也可以完成工作时,避免锁定 this 是更可取的.

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

<小时>

一些进一步的信息(在给出答案时更新):

  • 我们正在讨论实例同步
  • 同时考虑隐式(synchronized 方法)和显式形式的synchronized(this)
  • 如果您引用 Bloch 或其他有关该主题的权威,请不要遗漏您不喜欢的部分(例如 Effective Java,关于线程安全的项目:通常它是实例本身的锁,但是有例外.)
  • 如果您需要 synchronized(this) 提供之外的锁定粒度,则 synchronized(this) 不适用,所以这不是问题

解决方案

我将分别介绍每个点.

  1. <块引用>

    一些邪恶的代码可能会偷走你的锁(这个很流行,也有一个意外"变体)

    我更担心意外.这意味着 this 的这种使用是您的类公开接口的一部分,应该记录在案.有时需要其他代码使用您的锁的能力.Collections.synchronizedMap 之类的东西也是如此(参见 javadoc).

  2. <块引用>

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

    这是过于简单化的想法;只是摆脱 synchronized(this) 不会解决问题.适当的吞吐量同步需要更多考虑.

  3. <块引用>

    你(不必要地)暴露了太多信息

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

Whenever a question pops up on SO about Java synchronization, some people are very eager to point out that synchronized(this) should be avoided. Instead, they claim, a lock on a private reference is to be preferred.

Some of the given reasons are:

  • some evil code may steal your lock (very popular this one, also has an "accidentally" variant)
  • all synchronized methods within the same class use the exact same lock, which reduces throughput
  • you are (unnecessarily) exposing too much information

Other people, including me, argue that synchronized(this) is an idiom that is used a lot (also in Java libraries), is safe and well understood. It should not be avoided because you have a bug and you don't have a clue of what is going on in your multithreaded program. In other words: if it is applicable, then use it.

I am interested in seeing some real-world examples (no foobar stuff) where avoiding a lock on this is preferable when synchronized(this) would also do the job.

Therefore: should you always avoid synchronized(this) and replace it with a lock on a private reference?


Some further info (updated as answers are given):

  • we are talking about instance synchronization
  • both implicit (synchronized methods) and explicit form of synchronized(this) are considered
  • if you quote Bloch or other authorities on the subject, don't leave out the parts you don't like (e.g. Effective Java, item on Thread Safety: Typically it is the lock on the instance itself, but there are exceptions.)
  • if you need granularity in your locking other than synchronized(this) provides, then synchronized(this) is not applicable so that's not the issue

解决方案

I'll cover each point separately.

  1. Some evil code may steal your lock (very popular this one, also has an "accidentally" variant)

    I'm more worried about accidentally. What it amounts to is that this use of this is part of your class' exposed interface, and should be documented. Sometimes the ability of other code to use your lock is desired. This is true of things like Collections.synchronizedMap (see the javadoc).

  2. All synchronized methods within the same class use the exact same lock, which reduces throughput

    This is overly simplistic thinking; just getting rid of synchronized(this) won't solve the problem. Proper synchronization for throughput will take more thought.

  3. You are (unnecessarily) exposing too much information

    This is a variant of #1. Use of synchronized(this) is part of your interface. If you don't want/need this exposed, don't do it.

这篇关于在 Java 中避免同步(this)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:在 Java 中避免同步(this)?