可重入锁 - Java 并发实践

Reentrant lock - Java concurrency in practice

这是一些示例代码,用于从 'Java concurrency in practice':

重新 运行t 锁定
class Widget {
public synchronized void doSomething() {
    System.out.println(toString() + ": calling superclass doSomething");
}


}

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

书上解释说在上面的代码中... "Because the doSomething methods in Widget and LoggingWidget are both synchronized, each tries to acquire the lock on the Widget before proceeding."

我运行以上代码观察内在锁。上面的引用似乎暗示线程获取了 Widget 对象的内部锁,但我观察到的是线程获取了 LoggingWidget 的锁。我不确定如何验证获取计数,因此无法观察到。

这本书使用的名称 LoggingWidget/Widget 是可以互换的还是我应该专门观察 Widget 对象上的锁?

编辑:完整摘录

Reentrancy facilitates encapsulation of locking behavior, and thus simplifies the development of object-oriented concurrent code. Without reentrant locks, the very natural-looking code in Listing 2.7 , in which a subclass overrides a synchronized method and then calls the superclass method, would deadlock. Because the doSomething methods in Widget and LoggingWidget are both synchronized, each tries to acquire the lock on the Widget before proceeding. But if intrinsic locks were not reentrant, the call to super.doSomething would never be able to acquire the lock because it would be considered already held, and the thread would permanently stall waiting for a lock it can never acquire. Reentrancy saves us from deadlock in situations like this.

我需要看到摘录才能给你一个具体的答案。您可以用不同的方式实例化那些 classes。锁在对象上,所以引用是什么并不重要。为了说明...

这个 class 结构与您的非常相似。

public class GenericTest {
    public static void main(String... args) {
        Sub sub = new Sub();
        sub.go();
    }

    public synchronized void go() {
        System.out.println("Parent");
    }
}

class Sub extends GenericTest {
    @Override
    public synchronized void go() {
        System.out.println("Child");
        super.go();
    }
}

运行 这个程序,并在用你喜欢的方法(比如 System.in.read())获得锁后停止执行更多行。找到java程序的pid,在Jconsole中打开。移动到 threads 部分并在每次获取锁时突出显示它。您会看到以下痕迹。

my.package.common.GenericTest.go(GenericTest.java:30)
   - locked my.package.common.Sub@4c767286
my.package.common.Sub.go(GenericTest.java:42)
   - locked my.package.common.Sub@4c767286

因为这个方法是一个成员变量,所以锁定在执行相关方法的当前对象 (this) 上。注意 Sub@4c767286.

上的两个锁

[编辑]

编辑我的答案以适合您的具体情况。

是的,作者可以互换使用 LoggingWidget/Widget,因为根据 OOP 继承原则,LoggingWidget 对象也是一个 Widget class 对象。例子中只会创建一个对象实例,作为同步监视器重新进入。