Monitors or ObjectMonitors are a multithreading construct, they rely on the OS’ mutex lock primitive and when created are a part of an object, used to track its ownership (Which thread has the object’s lock). Because of this they are also known as intrinsic locks.
Monitors are part of a larger system that help control ownership of specific objects with the synchronize keyword.
They are not Java Objects, instead, ObjectMonitors are native C++ structs and are allocated in a portion of the heap that is managed directly by the JVM and is not GC’d.
They contain:
- Native OS Mutex (the lock)
- Pointer to the currently owning thread
- Entry Set - Set of threads that are blocked, waiting to acquire the lock
- Wait Set - Set of threads that called
wait()
in asynchronized
block and thus temporarily given up the lock - Displaced Header - metadata of the object
When is a Monitor Created?
1 Monitor always belongs to 1 object, but not all objects have monitors at any given time. Monitors are only created when threads are in contention for ownership over a single object.
As for why a Monitor isn’t needed when only a single thread is locking an object, see how the object header efficiently handles such cases.
Example of when a Monitor is created for an object
class Main {
public static void main(String[] args) {
ThreadSafeCounter counter = new ThreadSafeCounter();
// This thread calls this method on an instance of ThreadSafeCounter,
// No monitor is created, as only 1 thread is contending for the lock
new Thread(()-> counter.incr()).start();
// This thread then calls a method on the same instance,
// while the first thread is still running the incr() method.
// Now a Monitor is created as 2 threads are contending for ownership of the same object
new Thread(()-> counter.get()).start();
}
}
class ThreadSafeCounter {
private int count = 0;
public synchronized int get(){
return count;
}
public synchronized void incr() {
// artificially delay this method
try { Thread.sleep(1000); } catch(InterruptedException _e) {}
count++;
}
}