首页 > 解决方案 > 获取对象监视器锁的线程是否也获取超类的对象锁?

问题描述

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

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

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

已查看有关同步和内在锁的文章 -内在锁对 Java 类实际上意味着什么? https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

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) {}
    }
}

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

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

标签: multithreadingsynchronizationsynchronizedthread-synchronization

解决方案


我不确定你的问题是否有意义。没有“超类”实例这样的东西,因为子类的实例是一个并且与其超类的实例相同,否则每次使用new关键字时都会实例化多个对象。这也是您不能执行以下操作的原因:

synchronized (super) {
}

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

因此,由于AB都是 的同一个实例,因此您是否已同步并调用fromObject并不重要,它们都指的是同一个。BwaitAObject


推荐阅读