同步块中的静态与非静态锁定对象

ADT*_*DTC 36 java static synchronization locking synchronized

尝试可视化和理解同步.

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

代码A.

public class MyClass1 {
  private static final Object lock = new Object();
  public MyClass1() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}
Run Code Online (Sandbox Code Playgroud)

代码B.

public class MyClass2 {
  private final Object lock = new Object();
  public MyClass2() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}
Run Code Online (Sandbox Code Playgroud)

注意

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

我已经在这个问题中查看了答案,但不清楚不同的使用场景是什么.

Joa*_*uer 50

区别很简单:如果锁定的对象在一个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

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

根据经验,您希望锁定对象具有与static操作值相同的性质.因此,如果操作非静态值,则需要非静态锁定对象.如果操作静态值,则需要静态锁定对象.

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

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