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?
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
.