以下是一些示例代码,用于在实践中对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();
}
}
这本书在上面的代码中解释了...... "因为Widget和LoggingWidget中的doSomething方法都是同步的,所以每个方法都会在继续之前尝试获取Widget上的锁。"
我运行上面的代码来观察内在锁。上面的引用似乎暗示一个线程获取Widget对象的内部锁,但我观察到的是该线程获取了LoggingWidget上的锁。我不确定如何验证采集计数,因此无法观察到。
这本书是否可以互换地使用名称LoggingWidget / Widget,还是我应该专门观察Widget对象的锁定?
编辑:完整摘录
重入有助于封装锁定行为,因此 简化了面向对象的并发代码的开发。没有 重入锁,清单2.7中非常自然的代码,in 哪个子类重写同步方法然后调用 超类方法,会死锁。因为doSomething方法在 Widget和LoggingWidget都是同步的,每个都尝试获取 在继续之前锁定Widget。但如果内在锁定 不可重入,对super.doSomething的调用永远不会 获得锁定,因为它将被视为已经持有,并且 线程将永久停止等待锁定它永远不会 获得。在这样的情况下,重入可以使我们免于死锁。
答案 0 :(得分:7)
我需要看一段摘录给你一个具体的答案。您可以以不同的方式实例化这些类。锁定在对象上,因此引用无关紧要。为了说明......
这个类结构与你的模仿结构非常相似。
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
上。
[编辑]
根据您的具体情况编辑我的答案。
答案 1 :(得分:4)
是的,作者可以互换地使用LoggingWidget / Widget,因为根据OOP继承原则,LoggingWidget对象也是一个Widget类对象。在该示例中,将仅创建一个对象实例,并将其用作同步监视器以重新输入。