Why Reentrant Locks Prevent Deadlocks and How to Use Them in Java

Reentrant locks are thread‑safe synchronization tools that let the same thread acquire the same lock multiple times without deadlocking, tracking acquisition counts, and offering advantages over traditional synchronized blocks, with Java’s ReentrantLock providing flexible features such as interruptible and timed locking, illustrated by a complete code example.

Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Why Reentrant Locks Prevent Deadlocks and How to Use Them in Java

Reentrant Lock (Reentrant Lock) is a thread‑safe lock that allows the same thread to acquire the same lock multiple times without causing deadlock.

How Reentrant Locks Work

When a thread attempts to acquire a lock, the lock is marked as occupied; other threads are blocked. A reentrant lock tracks the acquisition count per thread, allowing the same thread to lock repeatedly.

First acquisition: the thread obtains the lock and the counter is set to 1.

Second acquisition: the same thread obtains the lock again, and the counter increases to 2.

The lock is fully released only after the thread releases it enough times for the counter to return to 0, allowing other threads to acquire it.

Key Features of Reentrant Locks

Same thread can acquire the lock multiple times without blocking.

Avoids deadlock because the lock records acquisition count.

Each acquisition must be released; failing to do so can cause resource leaks or deadlock.

Differences Between Reentrant Locks and Regular Locks

Regular locks such as Java's synchronized cause deadlock if the same thread re‑enters because they do not track acquisition count. Reentrant locks avoid this by recording how many times each thread has acquired the lock, allowing safe re‑entry.

ReentrantLock in Java

In Java, the ReentrantLock class in java.util.concurrent.locks is the most common reentrant lock implementation. It is reentrant and offers stronger control than synchronized, including interruptible lock requests, try‑lock, and timed locking.

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock();

    public void methodA() {
        lock.lock(); // acquire lock
        try {
            System.out.println("Thread " + Thread.currentThread().getName() + " is in methodA");
            methodB(); // call methodB in the same thread
        } finally {
            lock.unlock(); // release lock
        }
    }

    public void methodB() {
        lock.lock(); // acquire lock again
        try {
            System.out.println("Thread " + Thread.currentThread().getName() + " is in methodB");
        } finally {
            lock.unlock(); // release lock
        }
    }
}

In this example, methodA calls methodB, and both methods need to acquire the same ReentrantLock. Without a reentrant lock, methodB would deadlock because thread A already holds the lock; with ReentrantLock, thread A can acquire the lock repeatedly, avoiding deadlock.

Advantages and Considerations of Reentrant Locks

Advantages

Avoid deadlock: the same thread can repeatedly acquire the lock safely.

Flexibility: provides features such as interruptible lock requests, try‑lock, timed lock, etc., beyond what synchronized offers.

Precautions

Lock release: ensure each acquisition is eventually released to prevent resource leaks or deadlock.

Not suitable for all scenarios: ReentrantLock requires explicit lock and unlock, making code more complex than using synchronized.

JavaconcurrencyThread SafetyReentrantLock
Xuanwu Backend Tech Stack
Written by

Xuanwu Backend Tech Stack

Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.