锁定获取订单

时间:2010-03-10 10:03:05

标签: java multithreading locking thread-safety

使用以下代码,如果一个线程调用LoggingWidget.doSomething(), 线程必须通过的锁获取顺序是什么? (即它首先获取Lock on LoggingWidget,然后获取Widget上的锁定吗?)

public class Widget {
   public synchronized void doSomething() {

   }
}

public class LoggingWidget extends Widget {
    public synchronized void doSomething() {
         System.out.println(toString() + ": calling doSomething");
         super.doSomething();
    }
}

4 个答案:

答案 0 :(得分:3)

这种情况下的锁定在this上,因此只有一个锁,即实例。如果有多个实例,则每个实例都具有完全独立的锁定,无论它是Widget还是LoggingWidget

让我换一种说法。您的代码在语义上等同于:

public class Widget {
  public void doSomething() {
    synchronized (this) {
      // do stuff
    }
  }
}

public class LoggingWidget extends Widget {
  public void doSomething() {
    synchronized (this) {
      System.out.println(toString() + ": calling doSomething");
      super.doSomething();
    }
  }
}

只调用其中一个方法,因此只有一个锁。

答案 1 :(得分:1)

在Java中,它们是caleld监视器并且是每个对象。在您的示例中,只有一个监视器。

答案 2 :(得分:1)

只有一个锁bcoz只有一个对象,但如果调用子类对象的doSomething()方法,则会获取两次相同的锁。在JVM中,所有者(线程)是相同的,但它将获取计数设置为两个每次拥有线程存在同步块时,采集计数会减少。所以在这里,当最终释放锁时,它将减少两次,降至零,每个同步块一个。

答案 3 :(得分:0)

如果你想确保你获得LoggingWidget类型的正确锁定而不是Widget,你可以这样做:

public class LoggingWidget extends Widget {
  private final Object readLock = new Object();

  public void doSomething() {
    synchronized (readLock) {
      System.out.println(toString() + ": calling doSomething");
      super.doSomething();
    }
  }
}

或者如果你使用Lombok,你可以写

public class LoggingWidget extends Widget {
  @Synchronized("readLock")
  public void doSomething() {
    System.out.println(toString() + ": calling doSomething");
      super.doSomething();
  }
}