ReentrantReadWriteLock maintains a pair of locks: one for read-only operations and one for write operations. Multiple threads can hold the read lock simultaneously (shared access), but the write lock is exclusive.

Lock Acquisition Rules

  • Multiple readers: Can hold the read lock simultaneously
  • Single writer: Write lock is exclusive - blocks all readers and writers
  • No mixed access: Cannot have readers and writers at the same time

When to Use

Best suited for read-heavy workloads where reads significantly outnumber writes.
If writes are frequent, the overhead of managing two locks may outweigh the benefits.
Consider using a simple ReentrantLock instead for write-heavy scenarios.

Fairness

Like ReentrantLock, supports an optional fairness parameter:
new ReentrantReadWriteLock(boolean fair)

This prevents barging, reducing the probability of thread starvation.
However, it doesn’t prevent starvation as that ultimately depends on the OS thread scheduler.

Fair mode caveats:

  • Prevents writer starvation (readers won’t monopolise the lock indefinitely)
  • Lower throughput compared to non-fair mode
  • tryLock() methods still skip the FIFO queue

see ReentrantLock for more details on fairness

Write Lock Downgrading

Allowed: Write lock → Read lock (acquire read before releasing write)

writeLock.lock();
try {
    // modify data
    readLock.lock();  // Downgrade: acquire read lock
} finally {
    writeLock.unlock();  // Release write lock (still hold read lock)
}
try {
    // continue reading
} finally {
    readLock.unlock();
}

NOT Allowed: Read lock → Write lock (causes deadlock)

readLock.lock();
writeLock.lock();  // DEADLOCK - this will block forever

Thread States

Built on AbstractQueuedSynchronizer (AQS) using park/unpark mechanisms.
Threads waiting for locks are in WAITING or TIMED_WAITING states (NEVER BLOCKED).