Deep Dive into JUC’s ReentrantReadWriteLock – Source Code Walkthrough & Usage

This article explains the concepts, key features, internal implementation, and practical usage of Java's ReentrantReadWriteLock, illustrating how read and write locks interact, how fairness and lock downgrading work, and provides a complete code example with multithreaded readers and writers.

Programmer1970
Programmer1970
Programmer1970
Deep Dive into JUC’s ReentrantReadWriteLock – Source Code Walkthrough & Usage

Basic Concept of ReentrantReadWriteLock

ReentrantReadWriteLock is a re‑entrant read‑write lock that maintains two separate locks: a shared read lock that can be held by multiple threads simultaneously, and an exclusive write lock that only one thread can hold at a time.

Key Features

Re‑entrancy : The same thread can acquire the read lock or the write lock repeatedly without causing deadlock.

Fairness option : When constructing the lock you can choose a fair mode, which grants lock acquisition in FIFO order, or a non‑fair mode that may give higher throughput.

Lock downgrading : A thread may acquire the write lock, release it, and then acquire the read lock without releasing the lock entirely, useful for reading after a write.

Core Components

Sync : An abstract inner class extending AbstractQueuedSynchronizer that implements the core synchronization logic.

ReadLock : Implements Lock and delegates lock acquisition and release to the shared part of Sync.

WriteLock : Implements Lock and delegates exclusive lock operations to Sync.

Implementation Mechanism

State representation : A 32‑bit state field where the high 16 bits count read locks and the low 16 bits count write locks.

Write lock acquisition : Sync.tryAcquire(int acquires) succeeds only when state == 0; on success it increments the low 16 bits and records the owner thread.

Read lock acquisition : Sync.tryAcquireShared(int acquires) succeeds when the low 16 bits are zero; on success it increments the high 16 bits.

Lock release : tryRelease decrements the low 16 bits for write locks; tryReleaseShared decrements the high 16 bits for read locks. When state becomes zero, waiting threads are unblocked.

Fairness handling : The constructor can create either FairSync or NonfairSync, which differ in how they order threads in the wait queue.

Source‑code Skeleton

public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
    // Abstract inner class Sync extends AbstractQueuedSynchronizer
    abstract static class Sync extends AbstractQueuedSynchronizer {
        // ... other fields and methods ...
        final boolean tryAcquire(int acquires) { /* ... */ }
        final boolean tryRelease(int releases) { /* ... */ }
        final int tryAcquireShared(int acquires) { /* ... */ }
        final boolean tryReleaseShared(int releases) { /* ... */ }
        final boolean isHeldExclusively() { /* ... */ }
    }
    static final class NonfairSync extends Sync { /* ... */ }
    static final class FairSync extends Sync { /* ... */ }
    public static final class ReadLock implements Lock, java.io.Serializable {
        public void lock() { sync.acquireShared(1); }
        public void unlock() { sync.releaseShared(1); }
    }
    public static final class WriteLock implements Lock, java.io.Serializable {
        public void lock() { sync.acquire(1); }
        public void unlock() { sync.release(1); }
    }
}

Practical Usage Example

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private int counter = 0;
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();

    public int readCounter() {
        readLock.lock();
        try {
            Thread.sleep(10);
            return counter;
        } catch (InterruptedException e) { e.printStackTrace(); return -1; }
        finally { readLock.unlock(); }
    }

    public void incrementCounter() {
        writeLock.lock();
        try {
            Thread.sleep(10);
            counter++;
        } catch (InterruptedException e) { e.printStackTrace(); }
        finally { writeLock.unlock(); }
    }

    class ReaderThread extends Thread {
        @Override public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("Reader" + Thread.currentThread().getId() + " reads: " + readCounter());
            }
        }
    }

    class WriterThread extends Thread {
        @Override public void run() {
            for (int i = 0; i < 5; i++) {
                incrementCounter();
                System.out.println("Writer" + Thread.currentThread().getId() + " increments");
            }
        }
    }

    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();
        for (int i = 0; i < 3; i++) {
            new Thread(example.new ReaderThread()).start();
            new Thread(example.new WriterThread()).start();
        }
    }
}

Important Usage Notes

Avoid lock upgrade : Trying to acquire a write lock while holding a read lock leads to deadlock; design code to acquire the needed lock type from the start.

Respect mutual exclusion : Multiple readers can coexist, but a writer excludes all other readers and writers. Improper use can degrade performance or cause deadlock.

Choose fairness wisely : Fair locks guarantee FIFO ordering, preventing starvation, while non‑fair locks may offer higher throughput in low‑contention scenarios.

ReentrantReadWriteLock diagram
ReentrantReadWriteLock diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencyMultithreadingJUCReadWriteLockReentrantReadWriteLock
Programmer1970
Written by

Programmer1970

Formerly called 'Code to 35'. Add our main WeChat ID to access a wealth of shared resources (algorithms, interview prep, tech stacks: Java, Python, Go, big data). We mainly share serious development techniques, focusing on output-driven input. Occasionally we post life snippets and gossip. Our aim is to attract precise traffic and test advertising opportunities.

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.