π Custom Reader-Writer Lock in Java
π Problem Statement
Section titled βπ Problem StatementβA Reader-Writer Lock allows:
- Multiple threads to read a resource simultaneously
- But only one thread to write, and writers must have exclusive access
This solution implements:
β
Thread-safe access
β
Prevention of writer starvation
β
Multiple readers, one writer at a time
β Constraints
Section titled ββ Constraintsβ- Multiple Readers: Multiple threads can read simultaneously when no writer is active
- Exclusive Writer: Only one writer can access the resource at a time
- Writer Priority: Writers should not starve due to continuous reader access
- Thread Safety: Must handle concurrent access from multiple reader and writer threads
- No Deadlocks: Solution must not deadlock under any circumstances
- Fair Access: Both readers and writers should get reasonable access to the resource
π₯ Input / Output
Section titled βπ₯ Input / OutputβInput:
- Multiple reader threads requesting read access
- Multiple writer threads requesting write access
- Shared resource that needs protection
Output:
- Controlled access to the shared resource
- Multiple concurrent readers when safe
- Exclusive writer access when needed
- Proper synchronization without deadlocks
π‘ Intuition About Solving This Problem
Section titled βπ‘ Intuition About Solving This ProblemβThe key insight is that we need to track three pieces of state: current readers, current writers, and pending write requests. Readers can proceed when there are no active writers or pending write requests. Writers can proceed when there are no active readers or writers. The write request counter prevents writer starvation by giving priority to writers over new readers.
π Steps to Take to Solve
Section titled βπ Steps to Take to Solveβ- Design the state variables: Track readers, writers, and write requests
- Implement read lock acquisition: Allow multiple readers when no writers active
- Implement write lock acquisition: Ensure exclusive access for writers
- Handle write requests: Track pending writes to prevent reader starvation
- Implement proper release: Decrement counters and notify waiting threads
- Add safety checks: Ensure proper state transitions
β οΈ Edge Cases to Consider
Section titled ββ οΈ Edge Cases to Considerβ- Writer starvation: Handle when readers continuously acquire locks
- Reader starvation: Handle when writers continuously acquire locks
- Concurrent releases: Handle multiple threads releasing locks simultaneously
- Thread interruption: Handle InterruptedException properly
- Spurious wakeups: Use while loops to check conditions after waking up
- State consistency: Ensure counters never go negative
π» Code (with comments)
Section titled βπ» Code (with comments)β/** * A reader-writer lock that allows multiple readers to access a resource * simultaneously, but only one writer at a time. */public class ReaderWriterLock { private int readers = 0; // Current number of active readers private int writers = 0; // Current number of active writers private int writeRequests = 0; // Number of threads waiting to write
public synchronized void acquireReadLock() throws InterruptedException { // Wait until there are no active writers or pending write requests while (writers > 0 || writeRequests > 0) { wait(); } readers++; // Increment reader count }
public synchronized void releaseReadLock() { readers--; // Decrement reader count if (readers == 0) { notifyAll(); // Notify waiting writers when no readers remain } }
public synchronized void acquireWriteLock() throws InterruptedException { writeRequests++; // Increment write request count to prevent new readers // Wait until there are no active readers or writers while (readers > 0 || writers > 0) { wait(); } writeRequests--; // Decrement write request count writers++; // Increment writer count }
public synchronized void releaseWriteLock() { writers--; // Decrement writer count notifyAll(); // Notify all waiting threads }
public synchronized int getReaderCount() { return readers; // Return current number of active readers }
public synchronized boolean isWriteLocked() { return writers > 0; // Check if any writer is currently active }
public synchronized int getWriteRequests() { return writeRequests; // Return number of pending write requests }}π Dry Run Example
Section titled βπ Dry Run ExampleβScenario: 2 readers and 1 writer competing for access
Initial State:
- readers = 0, writers = 0, writeRequests = 0
Step 1: Reader 1 wants to read
- Check: writers > 0 || writeRequests > 0 β false (0 > 0 || 0 > 0)
- Increment readers to 1
- Reader 1 can proceed
Step 2: Reader 2 wants to read
- Check: writers > 0 || writeRequests > 0 β false (0 > 0 || 0 > 0)
- Increment readers to 2
- Reader 2 can proceed
Step 3: Writer wants to write
- Increment writeRequests to 1
- Check: readers > 0 || writers > 0 β true (2 > 0 || 0 > 0)
- Writer waits
Step 4: Reader 1 finishes reading
- Decrement readers to 1
- readers != 0, so no notification
- Writer still waits
Step 5: Reader 2 finishes reading
- Decrement readers to 0
- readers == 0, so notifyAll()
- Writer wakes up and checks: readers > 0 || writers > 0 β false (0 > 0 || 0 > 0)
- Decrement writeRequests to 0
- Increment writers to 1
- Writer can proceed
Result: Multiple readers can read simultaneously, writer gets exclusive access when no readers remain.
β±οΈ Time Complexity / Space Complexity
Section titled ββ±οΈ Time Complexity / Space ComplexityβTime Complexity:
- Read lock acquisition: O(1) - constant time to check conditions and update state
- Write lock acquisition: O(1) - constant time to check conditions and update state
- Lock release: O(1) - constant time to update state and notify threads
- Waiting time: O(1) - constant time to block/unblock threads
Space Complexity:
- State variables: O(1) - constant space for counters
- Thread management: O(1) - constant space regardless of number of threads
- Synchronization overhead: O(1) - constant space for intrinsic locks
π Usage Example
Section titled βπ Usage ExampleβReaderWriterLock lock = new ReaderWriterLock();
// Reader threadnew Thread(() -> { try { lock.acquireReadLock(); System.out.println("π Reading data..."); Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.releaseReadLock(); }}).start();
// Writer threadnew Thread(() -> { try { lock.acquireWriteLock(); System.out.println("βοΈ Writing data..."); Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.releaseWriteLock(); }}).start();π Key Features
Section titled βπ Key Featuresβ| Feature | Description |
|---|---|
| π₯ Multiple Concurrent Readers | Readers can access simultaneously if no writer is active |
| π§ββοΈ Exclusive Writer Access | Only one writer allowed, no readers during writing |
| β³ Writer Priority | Prevents writer starvation by delaying new readers |
| π Thread Safe | All methods are synchronized |
| π‘οΈ Deadlock Prevention | Proper wait/notify management avoids deadlocks |
β Summary
Section titled ββ SummaryβThis ReaderWriterLock class:
- Balances concurrency and data integrity
- Enables fine-grained access control
- Prioritizes fairness and avoids starvation