当前位置: 首页 > 知识库问答 >
问题:

线程获取对象的监视器锁也获取超类的对象锁吗?

艾成益
2023-03-14

当一个线程获得一个对象(比如类B)的监控锁时,它是否获得了属于它的超类(比如类A,其中B扩展了A)的对象的监控锁?

观察 #1 - 当一个线程(通过同步方法拥有派生对象 B 的监视器锁)在超类 A 中调用 wait() 时,第二个线程获取对象 B 的监视器锁并在 A 中进行等待。最后,两个线程同时退出 B 的对象监视器。

我的理解是线程应该在其拥有锁的对象上调用wait(),否则这将导致非法监视器状态异常。在 A 的实例方法中调用 wait() 时没有异常的原因,是否意味着拥有 B 对象锁的线程也拥有 A 对象的锁,它是超类?

关于同步的已检查文章

public class Obs2 {
    public static void main(String[] args) {
        A a = new B();
        Thread t1 = new Thread(a);
        Thread t2 = new Thread(a);
        t1.start(); t2.start();
    }
}

class A implements Runnable {
    public void run() {
        try {
            wait(2000); // OK; No IllegalMonitorStateException
        } catch (InterruptedException e) {}
    }
}
class B extends A {
    @Override
    public synchronized void run() {
        super.run();
    }
}

观察#2-当线程(通过同步方法拥有对象a的监视器锁)在任意类C中调用wait()时,它会引发IllegalMonitorStateException。

这表明线程在C的对象上调用wait(),而它拥有不同的对象A的锁。因此出现了例外。

public class Obs2 {
    public static void main(String[] args) {
        A a = new A();
        Thread t1 = new Thread(a);
        Thread t2 = new Thread(a);
        t1.start(); t2.start();
    }

}

class A implements Runnable {
    public synchronized void run() {
        (new C()).display(this);
    }

}

class C {
    public void display() {
        try {
            wait(2000); //--> will lead to IllegalMonitorStateException
        } catch (InterruptedException e) {}
    }
}

为什么与任何其他类相比,对象监视器锁对超类的行为方式存在这种固有差异?

我对对象监视器锁的理解是否遗漏了什么?

共有1个答案

孟振
2023-03-14

我不确定你的问题是否有意义。没有“超类”实例这样的东西,因为子类的实例与其超类的实例相同,否则每次使用 new 关键字时都会实例化多个对象。这也是为什么你不能做这样的事情的原因:

synchronized (super) {
}

最终,使用等待通知[全部]的能力属于Object(因为它们是最终方法),这是每个类的超超类。您可以将在this上同步视为在属于Object的监视器上同步,因为内在锁与对象而不是类相关联(一个重要的区别是可以获取与class对象相关联的内在锁)。

因此,由于 A 和 B 都是 Object 的同一实例,因此您在 B 中同步并从 A 调用 wait 并不重要,它们都引用同一个对象

 类似资料:
  • 问题内容: 我想知道是否有一种方法可以通过评估在运行时获取其值的类的对象,在运行时使用@conditionalonexpression来启用类。 例如: propertyobject实例在运行时填充了值(在程序开始时说)是否可以实现? 问题答案: 是的,可以,但是方法应该是静态的。 喜欢:

  • 问题内容: 如果知道与该线程关联的ID,该如何获取正在运行的线程的引用? 例如 问题答案: 您有2种方法可以做到。两者都很简单: 旧方法:获取您可以循环访问..getParent()的根线程组。并打电话 较新(但速度较慢)。 第一种方法有一个小问题,由于存在错误,ThreadGroup可能根本无法枚举任何东西。 第二个比较慢,但是有安全漏洞。

  • 问题内容: 我有一个Web应用程序,并且正在使用Oracle数据库,并且有一种基本上像这样的方法: 现在没有任何类型的同步,因此n个线程当然可以自由地访问此方法,当2个线程都进入此方法都进行检查并且当然还没有任何东西时,就会出现问题,然后它们都可以提交事务并创建一个重复的对象。 我不想在数据库中使用唯一的密钥标识符来解决此问题,因为我认为我不应该抓住它。 我也不能在提交之前进行检查,因为不仅要进行

  • 从这段代码中我可以理解,一个线程一旦进入方法,就获取inst1上的锁,然后获取inst2上的锁,而不释放inst1锁。我假设这两个对象都没有被其他线程锁定。< br> 如果一个线程一次只能获得一个对象的锁,并且在当前对象的锁被释放时只能拥有另一个锁,那么这段代码怎么可能是有效的,或者更确切地说,它是我认为我在某个地方看到的有效代码吗? 如果Type1和Type2是相同的呢? 如果我们使方法同步,考

  • 问题内容: 我创建了一个JavaScript对象,但是如何确定该对象的类呢? 我想要一些类似于Java的方法。 问题答案: JavaScript中没有Java的完全对应版本。通常,这是由于JavaScript是一种基于原型的语言,而不是Java是一种基于类的语言。 一些例子: 注意:如果使用Uglify编译代码,它将更改非全局类名。为了防止这种情况,Uglify有一个参数,可以使用gulp或gru

  • 问题内容: 有什么解决方案来获取对象的函数名称? -没有有关或的信息。有可能得到其中之一吗? 问题答案: 获取对象的构造函数,然后检查其name属性。 返回“ myClass”。