避免在Java中同步(this)?
每当有关于Java同步的SO问题出现时,有些人就非常希望指出应该避免synchronized(this)
。 相反,他们声称,锁定私人参考是首选。
一些给定的原因是:
包括我在内的其他人认为synchronized(this)
是一个习惯用法(在Java库中也是如此),它是安全的并且很好理解。 它不应该被避免,因为你有一个错误,你不知道你的多线程程序正在发生什么。 换句话说:如果它适用,然后使用它。
我有兴趣看到一些真实世界的例子(没有foobar的东西),在synchronized(this)
也可以完成这项工作的时候避免锁定this
是可取的。
因此: 你应该总是避免synchronized(this)
并将其替换为私人引用上的锁?
更多信息(更新为答案):
synchronized
方法)和显式形式的synchronized(this)
synchronized(this)
提供,那么synchronized(this)
不适用,所以这不是问题 我会分别介绍每一点。
一些邪恶的代码可能会偷你的锁(非常受欢迎,也有一个“意外”的变体)
我更偶然地担心。 什么它相当于是这个用途this
是你的类暴露接口的一部分,并应记录在案。 有时需要其他代码使用您的锁的能力。 像Collections.synchronizedMap
(请参阅javadoc)这是事实。
同一类中的所有同步方法使用完全相同的锁,这会降低吞吐量
这是过于简单化的想法; 刚刚摆脱synchronized(this)
不会解决问题。 适当的吞吐量同步将需要更多思考。
你(不必要地)暴露太多的信息
这是#1的变体。 synchronized(this)
是您的界面的一部分。 如果你不想/需要这个暴露,不要这样做。
那么,首先应该指出的是:
public void blah() {
synchronized (this) {
// do stuff
}
}
在语义上等同于:
public synchronized void blah() {
// do stuff
}
这是不使用synchronized(this)
一个原因。 你可能会争辩说,你可以在synchronized(this)
块周围做些事情。 通常的原因是尽量避免必须进行同步检查,这会导致各种并发问题,特别是双重检查锁定问题,这些问题仅表明进行相对简单的检查是多么困难线程安全的。
私人锁是一种防御机制,这绝不是一个坏主意。
另外,正如你所提到的,私有锁可以控制粒度。 一个对象上的一组操作可能与另一个对象完全无关,但synchronized(this)
将相互排除对所有对象的访问。
synchronized(this)
只是真的不给你任何东西。
当您使用synchronized(this)时,您正在使用类实例作为锁本身。 这意味着虽然线程1获取锁定,但线程2应该等待
假设下面的代码
public void method1() {
do something ...
synchronized(this) {
a ++;
}
................
}
public void method2() {
do something ...
synchronized(this) {
b ++;
}
................
}
方法1修改变量a和方法2修改变量b,应该避免两个线程同时修改同一个变量,并且它是。 但是,当thread1修改a和thread2修改b时,它可以在没有任何竞态条件下执行。
不幸的是,上面的代码不会允许这样做,因为我们使用相同的引用来锁定; 这意味着即使它们不处于竞争状态,线程也应该等待,显然这些代码会牺牲程序的并发性。
解决方案是对两个不同的变量使用2个不同的锁。
class Test {
private Object lockA = new Object();
private Object lockB = new Object();
public void method1() {
do something ...
synchronized(lockA) {
a ++;
}
................
}
public void method2() {
do something ...
synchronized(lockB) {
b ++;
}
................
}
上面的例子使用了更细粒度的锁(2个锁而不是1个)(分别为变量a和b分别为lockA和lockB),因此可以实现更好的并发性,另一方面,它比第一个例子变得更加复杂。
链接地址: http://www.djcxy.com/p/2131.html上一篇: Avoid synchronized(this) in Java?
下一篇: IllegalArgumentException or NullPointerException for a null parameter?