Avoid synchronized(this) in Java?(在 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)
不适用,所以这不是问题
我将分别介绍每个点.
- <块引用>
一些邪恶的代码可能会偷走你的锁(这个很流行,也有一个意外"变体)
我更担心意外.这意味着
this
的这种使用是您的类公开接口的一部分,应该记录在案.有时需要其他代码使用您的锁的能力.Collections.synchronizedMap
之类的东西也是如此(参见 javadoc). - <块引用>
同一类中的所有同步方法都使用完全相同的锁,会降低吞吐量
这是过于简单化的想法;只是摆脱
synchronized(this)
不会解决问题.适当的吞吐量同步需要更多考虑. - <块引用>
你(不必要地)暴露了太多信息
这是#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 ofsynchronized(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, thensynchronized(this)
is not applicable so that's not the issue
I'll cover each point separately.
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 likeCollections.synchronizedMap
(see the javadoc).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.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)?
基础教程推荐
- 在螺旋中写一个字符串 2022-01-01
- 如何强制对超级方法进行多态调用? 2022-01-01
- Spring Boot Freemarker从2.2.0升级失败 2022-01-01
- Java 中保存最后 N 个元素的大小受限队列 2022-01-01
- 如何使用 Eclipse 检查调试符号状态? 2022-01-01
- 首次使用 Hadoop,MapReduce Job 不运行 Reduce Phase 2022-01-01
- 如何对 HashSet 进行排序? 2022-01-01
- 如何在不安装整个 WTP 包的情况下将 Tomcat 8 添加到 Eclipse Kepler 2022-01-01
- 由于对所需库 rt.jar 的限制,对类的访问限制? 2022-01-01
- 如何使用 Stream 在集合中拆分奇数和偶数以及两者的总和 2022-01-01