40

试图形象化和理解同步

  1. 同步块使用静态锁对象(代码 A)非静态锁对象(代码 B)有什么区别?
  2. 在实际应用中有何不同?
  3. 一个人会有哪些陷阱,而另一个人不会?
  4. 确定使用哪一个的标准是什么?

代码 A

public class MyClass1 {
  private static final Object lock = new Object();
  public MyClass1() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

代码 B

public class MyClass2 {
  private final Object lock = new Object();
  public MyClass2() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

笔记

上面的代码显示了构造函数,但您也可以讨论静态方法和非静态方法的行为有何不同。另外,当同步块修改静态成员变量时,使用静态锁是否有利?

我已经看过这个问题的答案,但是还不够清楚不同的使用场景是什么。

4

1 回答 1

56

区别很简单:如果锁定的对象在一个static字段中,那么所有的实例都MyClass*共享该锁(即没有两个对象能够同时锁定该对象)。

如果字段是非静态的,那么每个实例都会有自己的锁,所以只有在同一个对象上的方法调用才会相互锁定。

当您使用静态锁定对象时:

  • 线程 1 调用o1.foo()
  • 线程 2 调用o1.foo(),必须等待线程 1 完成
  • 线程 3 调用o2.foo()必须等待线程 1(可能还有 2)完成

当您使用非静态锁定对象时:

  • 线程 1 调用o1.foo()
  • 线程 2 调用o1.foo(),必须等待线程 1 完成
  • 线程 3 调用o2.foo(),它可以继续,不介意线程 1 和 2

您需要哪一个取决于您尝试使用同步块保护的数据类型。

根据经验,您希望锁定对象具有与static操作值相同的特性。因此,如果您只操作非静态值,您将需要一个非静态锁定对象。如果您操作静态值,您将需要一个静态锁定对象。

当您操作静态和非静态值时,它会变得复杂。简单的方法是只使用静态锁对象,但这可能会增加同步块的大小,超过绝对必要的程度,并且可能需要比预期更多的锁争用。在这些情况下,您可能需要静态和非静态锁定对象的组合。

在您的特定情况下,您在构造函数中使用锁,每个实例只会执行一次,因此非静态锁对象在这里没有任何意义。

于 2013-08-21T12:04:28.047 回答