使用以下代码,如果一个线程调用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();
}
}
答案 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();
}
}