Search code examples
multithreadingsynchronizationsynchronizedthread-synchronization

Does a thread acquiring monitor lock of object also acquires the object lock of superclass?


When a thread acquires monitor lock of an object (say class B) does it acquires the monitor lock of the object belonging to it's superclass (say class A, where B extends A) ?

Observation #1 - When a thread (that owns the monitor lock of derived object B through synchronized method) calls wait() inside superclass A, the second thread acquires object B's monitor lock and goes for waiting in A. Finally, both threads exit B's object monitor at the same time.

My understanding is a thread should invoke wait() on an object whose lock it owns, else this will lead to IllegalMonitorStateException. The reason that there being no exception while wait() called inside A's instance method, does it mean the thread owning the B object lock also owns the lock of A object, it's superclass ?

Checked articles on synchronization & intrinsic locks - What does intrinsic lock actually mean for a Java class? 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();
    }
}

Observation #2 - When a thread (that owns monitor lock of object A through synchronized method) invokes wait() inside any arbitrary class C, it raises an IllegalMonitorStateException.

This suggests the thread calls wait() on C's object whereas it owns the lock for object A which are different. Hence the exception.

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

Why this inherent discrepancy in the way the object monitor lock behaves for superclass in comparison to any other class ?

Is my understanding regarding object monitor lock missing anything?


Solution

  • I'm not exactly sure if your question makes any sense. There's no such thing as a "superclass" instance because the instance of the subclass is one and the same as the instance of its superclass, otherwise you would be instantiating several objects each time you use the new keyword. That is also the reason why you can't do something like:

    synchronized (super) {
    }
    

    Ultimately, the ability to use wait and notify[All] belongs to Object (as they are final methods), which is the super-super class of every class. You can think of synchronizing on this as synchronizing on the monitor belonging to Object, as intrinsic locks are associated with objects, not classes (an important distinction is that an intrinsic lock associated with a Class object may be acquired).

    Therefore, since both A and B are the same instance of Object, it doesn't matter that you've synchronized in B and call wait from A, they are both referring to the same Object.