在Java关键部分中,我应该同步什么?
在Java中,在代码中声明关键部分的惯用方式如下:
private void doSomething() {
// thread-safe code
synchronized(this) {
// thread-unsafe code
}
// thread-safe code
}
几乎所有的程序块都在this
同步,但是这有什么特别的原因吗? 还有其他的可能吗? 是否有什么最佳做法在什么对象上进行同步? (比如Object
私有实例?)
首先,请注意以下代码片段是相同的。
public void foo() {
synchronized (this) {
// do something thread-safe
}
}
和:
public synchronized void foo() {
// do something thread-safe
}
做同样的事情 。 除了代码的可读性和风格之外,没有任何一方偏好。
当你做同步方法或代码块时,知道你为什么要做这样的事情,以及你锁定什么对象以及为了什么目的很重要 。
还要注意的是,在某些情况下,您希望客户端同步代码块,其中您要求的监视器(即同步对象)不一定是this
,如下例所示:
Vector v = getSomeGlobalVector();
synchronized (v) {
// some thread-safe operation on the vector
}
我建议你获得更多有关并发编程的知识,一旦你知道幕后发生了什么,它会为你提供很多帮助。 您应该查看Java中的并发编程,这是一本关于这个主题的好书。 如果您想快速浏览该主题,请查看Java Concurrency @ Sun
正如前面的回答者已经指出的那样,最好的做法是在一个有限范围的对象上进行同步(换句话说,选择可以避开的最严格的范围,然后使用它)。特别是,同步this
是一个坏主意,除非你打算让你的班级的用户获得锁定。
但是,如果您选择在java.lang.String
上同步,则会出现一个特别难看的情况。 字符串可以(并且实际上几乎总是)被实施。 这意味着在ENTIRE JVM中每个相同内容的字符串在幕后都是相同的字符串。 这意味着,如果您在任何字符串上进行同步,则另一个(完全不同的)代码段也将锁定具有相同内容的字符串,实际上也会锁定您的代码。
我曾经在一个生产系统中解决了一个死锁问题,并且(非常痛苦地)将死锁跟踪到两个完全不同的开源软件包,每个开源软件包都在一个内容都是"LOCK"
的String实例上同步。
我尽量避免在this
上进行同步,因为这样可以让来自外部的所有参与该对象的人阻止我的同步。 相反,我创建了一个本地同步对象:
public class Foo {
private final Object syncObject = new Object();
…
}
现在我可以使用该对象进行同步,而不用担心任何人“窃取”该锁。
链接地址: http://www.djcxy.com/p/13315.html上一篇: In Java critical sections, what should I synchronize on?
下一篇: Preconditions library to throw IllegalArgumentException for notNull check