ReentrantLock

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • ReentrantLock is the most widely used implementation of the Lock interface in java.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:

  1. 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.
  2. Interruptibility: lockInterruptibly() allows a waiting thread to be interrupted and give up waiting, unlike synchronized which forces a thread to wait forever un-interruptibly.
  3. Condition Variables: You can create multiple Condition objects (lock.newCondition()) for a single lock, allowing for complex signaling (unlike the singular wait/notify per 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).