在 Java 关键部分中,我应该在哪些方面进行同步?

2022-08-31 13:06:22

在Java中,在代码中声明关键部分的惯用方法如下:

private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}

几乎所有的块都同步在 上,但是这有特殊的原因吗?还有其他可能性吗?对于要在哪个对象上进行同步,是否有任何最佳实践?(例如 ?的私有实例)thisObject


答案 1

正如前面的回答者所指出的那样,最佳做法是在作用域有限的对象上进行同步(换句话说,选择您可以逃脱的最严格的范围,然后使用它。特别是,在 上同步是一个坏主意,除非您打算允许类的用户获得锁定。this

但是,如果您选择在 .字符串可以(在实践中几乎总是)被拘禁。这意味着在整个JVM中,每个相同内容的字符串在幕后都是相同的字符串。这意味着,如果您在任何 String 上进行同步,则另一个(完全不同的)代码部分(也锁定了具有相同内容的 String)实际上也会锁定您的代码。java.lang.String

我曾经对生产系统中的死锁进行故障排除,并且(非常痛苦地)将死锁跟踪到两个完全不同的开源包,每个包都在String的一个实例上同步,其内容都是 。"LOCK"


答案 2

首先,请注意以下代码段是相同的。

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