【问题标题】:Reentrant lock - Java concurrency in practice可重入锁 - 实践中的 Java 并发
【发布时间】:2015-01-12 10:53:25
【问题描述】:

下面是一些“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 中看起来非常自然的代码,在 哪个子类覆盖同步方法,然后调用 超类方法,会死锁。因为 doSomething 方法在 Widget 和 LoggingWidget 都是同步的,各自尝试获取 在继续之前锁定小部件。但是如果内在锁是 不可重入,对 super.doSomething 的调用将永远无法 获取锁,因为它会被认为已经持有,并且 线程将永久停止等待它永远无法获得的锁 获得。在这种情况下,重入使我们免于陷入僵局。

【问题讨论】:

  • 一个线程死锁 - 对我来说看起来很奇怪

标签: java concurrency locking reentrancy


【解决方案1】:

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

这个类结构与你的非常相似。

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 上的两个锁。

[编辑]

根据您的具体情况编辑了我的答案。

【讨论】:

  • 为清楚起见添加了完整的摘录,但您的回答和@Semyon 的回答清楚地表明了这一点。很遗憾只能选择一个答案作为答案。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多