ReentrantLock
TL;DR
ReentrantLockis the most widely used implementation of theLockinterface injava.util.concurrent.locks.- It is reentrant, meaning a thread can acquire the same lock multiple times without deadlocking itself.
- It provides advanced features like fairness, interruptible lock acquisition, and timeouts.
Concept
The synchronized keyword inherently provides reentrancy. When the Java designers built the explicit Lock interface in Java 5, they provided ReentrantLock as the standard implementation so developers wouldn’t lose that vital feature.
Advanced Features of ReentrantLock:
- Fairness: By default, locks are unfair (whoever grabs it first gets it). You can initialize
new ReentrantLock(true)to make it fair: the longest-waiting thread gets the lock next, preventing starvation. - Interruptibility:
lockInterruptibly()allows a waiting thread to be interrupted and give up waiting, unlikesynchronizedwhich forces a thread to wait forever un-interruptibly. - Condition Variables: You can create multiple
Conditionobjects (lock.newCondition()) for a single lock, allowing for complex signaling (unlike the singularwait/notifyper object).
Examples
import java.util.concurrent.locks.ReentrantLock;
class SafePrinter {
// Creating a FAIR lock
private final ReentrantLock lock = new ReentrantLock(true);
public void printDocument(String document) {
lock.lock();
try {
System.out.println("Printing: " + document);
printFooter(); // Reentrancy in action
} finally {
lock.unlock();
}
}
public void printFooter() {
lock.lock(); // Thread already holds the lock, so it acquires it a 2nd time instantly
try {
System.out.println("Printing Footer");
} finally {
lock.unlock(); // Must unlock twice because we locked twice
}
}
}
Interview Questions
Q: What is a Reentrant Lock?
A: A reentrant lock allows a thread that currently holds the lock to re-acquire the exact same lock again without getting blocked. It maintains a hold count. If Thread A locks it, the count is 1. If Thread A calls another method that locks it again, the count is 2. The lock is only released to other threads when the hold count returns to 0 (meaning Thread A has called unlock() twice).
Q: What is the performance difference between ReentrantLock and synchronized?
A: Historically (Java 5/6), ReentrantLock was significantly faster under high contention. However, modern JVMs (Java 8+) have heavily optimized the intrinsic synchronized locks (using techniques like biased locking and lock coarsening). Today, their performance is practically identical. You should use synchronized for simplicity, and only use ReentrantLock if you specifically need its advanced features (timeouts, fairness).