Custom Reader-Writer Lock Implementation
๐ 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