在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