Use case: situations where reads are far more common than writes (config data, cache, wikipedia).
11.1 Reader Writer Lock
Reader/Writer Lock: A specialized lock abstract data type designed for this scenario. It permits:
- Multiple threads to hold the lock simultaneously for reading.
- OR, exactly one thread to hold the lock for writing.

Invariant: writers == 0 || readers == 0 (cannot have readers and writers concurrently) AND writers <= 1.
In Java:
synchronizeddoes not provide RW lock semantics.- Use
java.util.concurrent.locks.ReentrantReadWriteLock- It provides
readLock()andwriteLock()methods, returning separate Lock objects. You acquire/release these specific locks. - The default implementation has specific fairness policies (check docs) and does not support upgrading from a read lock to a write lock.
- It provides
11.1.1 Monitor-Based RW Lock Implementation
Java implementation of a basic RW lock with monitors.
class RWLock {
int writers = 0; // Count of active writers (0 or 1)
int readers = 0; // Count of active readers
synchronized void acquire_read() {
while (writers > 0) { // Wait if writer active
try { wait(); } catch (InterruptedException e) {}
}
readers++;
}
synchronized void release_read() {
readers--;
if (readers == 0) notifyAll(); // Wake waiting writers if last reader
}
synchronized void acquire_write() {
while (writers > 0 || readers > 0) { // Wait if writers OR readers active
try { wait(); } catch (InterruptedException e) {}
}
writers++;
}
synchronized void release_write() {
writers--;
notifyAll(); // Wake waiting readers/writers
}
}Fairness:
- This simple implementation has a reader preference.
- If the lock is held for reading, new readers can acquire it immediately, even if a writer is waiting.
- This can lead to writer starvation if reads are continuous.
11.1.2 Writer Priority RW Lock Implementation
We want to fix writer starvation using priority for writers.
class RWLock {
int writers = 0;
int readers = 0;
int writersWaiting = 0; // Count waiting writers
synchronized void acquire_read() {
// Wait if writer active OR if writer waiting
while (writers > 0 || writersWaiting > 0) {
try { wait(); } catch (InterruptedException e) {}
}
readers++;
}
// release_read is the same (notifyAll if readers == 0)
synchronized void acquire_write() {
writersWaiting++; // Indicate intent to write
while (writers > 0 || readers > 0) { // Wait if active reader/writer
try { wait(); } catch (InterruptedException e) {}
}
writersWaiting--; // No longer waiting
writers++; // Become active writer
}
// release_write is the same (writers--, notifyAll)
}Here when trying to read → we wait until all waiting writers have finished.
Fairness: Is this fair now? It prevents writer starvation but might now starve readers if writers arrive continuously. True fairness is complex.