内在/监视器锁和继承

5

背景:

我正在阅读《Java并发编程实践》,其中清单2.7有以下代码。该示例说明此代码之所以有效,是因为监视器锁是可重入的。

我最初可能会认为调用super.doSomething()时将获取基类对象而不是派生类对象上的锁。这意味着这种情况不需要重入性。尽管如此,我也明白基类和派生类方法都可以改变基类字段,所以它们使用的锁必须是公共的(这意味着我显然是错误的)。

问题:

在继承层次结构中,每个对象是否有一个“内部”锁,或者仅与继承层次结构中最终派生对象(或最少派生对象)相关联一个“内部”锁?


public class Widget {
    public synchronized void doSomething() {
        ...
    }
}

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

9
我本来认为当你调用super.doSomething()时,它会获取基类对象的锁而不是派生类对象的锁。
只有一个对象 - 如果您创建LoggingWidget的实例,则只创建一个对象,其中包含LoggingWidget和Widget的所有字段。它不像创建指向Widget实例的LoggingWidget实例。
只有一个对象,因此无论您在哪里同步它,都只有一个锁。

谢谢您的回答。出于好奇,C++在这方面工作方式是否相似,还是有所不同? - John Humphreys
如果我没记错的话,这是C++中“实现特定”的(众多!)领域之一。但是大多数实现只有一个对象。话虽如此,对象所在的内存通常被分成不同的块,每个块对应于层次结构中的每个类。 - yshavit
啊,这解释了我的困惑:)。我很确定在《Effective C++》中他们说过,如果你不将基类构造函数设为虚函数,就可能会删除基类内存并留下派生类内存泄漏,这让我认为它们是完全不同的对象。我只是在心里把它带到了Java上。 - John Humphreys
@w00te:这并不是可比较的,因为在C++中没有内在锁定机制... - Holger
@Holger - 是的,在C++中你需要使用互斥锁。我只是好奇在C++中一般情况下如何实例化类:)。不过还是谢谢你的警告! - John Humphreys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接