可重入锁 - 实践中的Java并发

sot*_*otn 4 java concurrency locking reentrancy

下面是一些用于"实践中的Java并发"的重入锁定的示例代码:

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();
}
}
Run Code Online (Sandbox Code Playgroud)

本书解释说,在上面的代码中......"因为Widget和LoggingWidget中的doSomething方法都是同步的,所以每个方法都会在继续之前尝试获取Widget上的锁定."

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

该书是否可以互换地使用名称LoggingWidget/Widget,还是应该特意观察Widget对象的锁定?

编辑:完整摘录

重入有助于封装锁定行为,从而简化了面向对象的并发代码的开发.如果没有重入锁,代码中非常自然的代码(其中子类重写synchronized方法然后调用超类方法)将会死锁.因为Widget和LoggingWidget中的doSomething方法都是同步的,所以每个方法都会在继续之前尝试获取Widget上的锁.但是如果内部锁不是可重入的,那么对super.doSomething的调用将永远无法获取锁,因为它将被认为已经被保持,并且线程将永久停止等待它永远无法获取的锁.在这样的情况下,可重入使我们免于死锁.

Dee*_*ala 9

我需要看一段摘录给你一个具体的答案.您可以以不同的方式实例化这些类.锁定在对象上,因此引用无关紧要.为了说明......

这个类结构非常类似于你的.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

运行此程序并在使用您喜欢的方法(例如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
Run Code Online (Sandbox Code Playgroud)

由于此方法是成员变量,因此锁定位于this执行相关方法的当前对象()上.注意两个锁是如何打开的Sub@4c767286.

[编辑]

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


小智 5

是的,作者可以互换使用LoggingWidget / Widget,因为根据OOP继承原理,LoggingWidget对象也是Widget类对象。在该示例中,将仅创建一个对象实例,并将其用作同步监视器以重新输入。