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

时间:2013-08-21 11:58:42

标签: java static synchronization locking synchronized

尝试可视化和理解同步

  1. 使用 静态锁定对象 (代码A) 非静态锁定之间有什么区别同步块的对象 (代码B)
  2. 在实际应用中有何不同?
  3. 另一方不会有什么陷阱?
  4. 确定使用哪一个的标准是什么?
  5. 代码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
      }
    }
    

    注意

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

    我已经在this question查看了答案,但不清楚不同的使用方案是什么。

1 个答案:

答案 0 :(得分:46)

区别很简单:如果锁定对象位于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 - ness。因此,如果您仅操作非静态值 ,则需要非静态锁定对象。如果您只操作静态值 ,则需要一个静态锁定对象。

当你操纵静态和非静态值时,它会变得复杂。 easy 方式只是使用静态锁定对象,但这可能会增加synchronized块的大小,而不是绝对必要,并且可能需要比预期更多的锁争用。在这些情况下,您可能需要静态和非静态锁定对象的组合。

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