Intrinsic Lock (Monitor Lock)
About
In Java, every object has an associated intrinsic lock (also known as a monitor lock), which is used for synchronization. The Java Virtual Machine (JVM) automatically associates a lock with every object to coordinate access among multiple threads.
When a thread enters a synchronized block or method, it must acquire the intrinsic lock of the associated object. Once acquired, other threads attempting to enter any synchronized section on the same object are blocked until the lock is released.
The intrinsic lock is also used in inter-thread communication via wait()
, notify()
, and notifyAll()
.
wait()
: Releases the lock and puts the thread in a waiting state.notify()
: Wakes up one waiting thread.notifyAll()
: Wakes up all waiting threads.
Intrinsic Lock Acquisition Process
Thread Tries to Enter a Synchronized Block or Method
If no other thread holds the object's lock, the thread acquires the lock and proceeds.
If another thread holds the lock, the current thread waits until the lock is released.
Thread Executes the Critical Section
The thread performs operations inside the synchronized block/method while holding the lock.
Thread Releases the Lock
After the synchronized block/method completes execution, the thread releases the lock, allowing other waiting threads to proceed.
Types of Intrinsic Lock Usage in Java
1. Synchronized Methods and Intrinsic Lock
When a method is declared as synchronized
, the intrinsic lock of the object (this
) is used.
Example: Synchronization Using Intrinsic Lock on an Object
class SharedResource {
public synchronized void displayMessage(String message) {
System.out.println(Thread.currentThread().getName() + " is executing: " + message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished execution.");
}
}
public class SynchronizedMethodExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
// Two threads trying to access the synchronized method
Thread t1 = new Thread(() -> resource.displayMessage("Hello from Thread-1"), "Thread-1");
Thread t2 = new Thread(() -> resource.displayMessage("Hello from Thread-2"), "Thread-2");
t1.start();
t2.start();
}
}
2. Synchronized Blocks and Intrinsic Lock
Instead of locking an entire method, synchronized blocks allow locking of specific code sections, improving efficiency.
Example: Synchronization Using an Intrinsic Lock on a Specific Object
class SharedResource {
private final Object lock = new Object();
public void displayMessage(String message) {
System.out.println(Thread.currentThread().getName() + " is preparing to execute.");
synchronized (lock) { // Only this block is synchronized
System.out.println(Thread.currentThread().getName() + " is executing: " + message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished execution.");
}
}
}
public class SynchronizedBlockExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread t1 = new Thread(() -> resource.displayMessage("Hello from Thread-1"), "Thread-1");
Thread t2 = new Thread(() -> resource.displayMessage("Hello from Thread-2"), "Thread-2");
t1.start();
t2.start();
}
}
3. Class-Level Synchronization and Intrinsic Lock on Class<T>
Class<T>
When a static
method is synchronized, the intrinsic lock is on the Class object (Class<T>
), ensuring that only one thread can execute any synchronized static method at a time.
Example: Synchronization Using Class-Level Lock
class SharedResource {
private static int counter = 0;
public static synchronized void increment() {
counter++;
System.out.println(Thread.currentThread().getName() + " incremented counter to: " + counter);
}
}
public class ClassLevelSyncExample {
public static void main(String[] args) {
Thread t1 = new Thread(SharedResource::increment, "Thread-1");
Thread t2 = new Thread(SharedResource::increment, "Thread-2");
t1.start();
t2.start();
}
}
Is the Intrinsic Lock Implicit or Explicit?
The intrinsic lock (monitor lock) in Java is an implicit lock, meaning:
It is automatically associated with every Java object.
It does not require explicit creation—it is acquired and released automatically when using
synchronized
.The JVM manages it internally, unlike
ReentrantLock
, which must be explicitly created and controlled.
Intrinsic Lock = Implicit Lock
When a thread enters a synchronized
method or block, it implicitly acquires the intrinsic lock of the associated object without needing manual intervention.
Example: Implicit Lock Using synchronized
class SharedResource {
public synchronized void displayMessage(String message) {
System.out.println(Thread.currentThread().getName() + " executing: " + message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished.");
}
}
public class IntrinsicLockExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread t1 = new Thread(() -> resource.displayMessage("Hello from Thread-1"), "Thread-1");
Thread t2 = new Thread(() -> resource.displayMessage("Hello from Thread-2"), "Thread-2");
t1.start();
t2.start();
}
}
Why Is It Implicit?
The lock is automatically acquired when
synchronized
is used.The lock is automatically released when the synchronized method/block completes execution.
No explicit lock handling (e.g.,
lock.lock()
andlock.unlock()
) is required.
Explicit Locks: How They Differ from Intrinsic Locks
Unlike intrinsic locks, explicit locks like ReentrantLock
must be manually controlled.
Example: Explicit Lock Using ReentrantLock
import java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private final ReentrantLock lock = new ReentrantLock();
public void displayMessage(String message) {
lock.lock(); // Explicitly acquiring the lock
try {
System.out.println(Thread.currentThread().getName() + " executing: " + message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // Explicitly releasing the lock
}
}
}
Equivalent Explicit Lock Code for Intrinsic Lock
1.1. Intrinsic Lock (Implicit) – Using synchronized
synchronized
class SharedResource {
// Implicitly using the intrinsic lock of 'this' object
public synchronized void displayMessage(String message) {
System.out.println(Thread.currentThread().getName() + " executing: " + message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished.");
}
}
1.2. Equivalent Explicit Lock – Using ReentrantLock
ReentrantLock
javaCopyEditimport java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private final ReentrantLock lock = new ReentrantLock(); // Explicit lock
public void displayMessage(String message) {
lock.lock(); // Manually acquiring the lock
try {
System.out.println(Thread.currentThread().getName() + " executing: " + message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // Manually releasing the lock
}
}
}
2.1. Intrinsic Lock – Using synchronized
Block
synchronized
Blockclass SharedResource {
public void displayMessage(String message) {
synchronized (this) { // Explicitly locking 'this' instance
System.out.println(Thread.currentThread().getName() + " executing: " + message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished.");
}
}
}
2.2. Equivalent Explicit Lock – Using ReentrantLock
in a Block
ReentrantLock
in a Blockimport java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private final ReentrantLock lock = new ReentrantLock();
public void displayMessage(String message) {
if (lock.tryLock()) { // Attempting to acquire the lock
try {
System.out.println(Thread.currentThread().getName() + " executing: " + message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // Releasing the lock
}
} else {
System.out.println(Thread.currentThread().getName() + " could not acquire lock.");
}
}
}
Last updated
Was this helpful?