ReentrantLock and Condition queues
advanced17 min readLesson 133 of 180
tryLock for deadlock avoidance, fairness tradeoffs, interruptibility, and one condition per predicate.
synchronized covers the basics. Real systems need what ReentrantLock
adds:
- tryLock: attempt acquisition now (or within a timeout) instead of
blocking forever. The backbone of deadlock avoidance — acquire two locks
with
tryLock+ backoff, or walk away. - Fairness:
new ReentrantLock(true)grants access in arrival order. Fair locks trade throughput for bounded waiting; default (unfair) lets a just-released thread re-acquire, which is usually what you want. - Interruptible acquisition:
lockInterruptibly()lets blocked threads respond to cancellation —synchronizedcannot. - Condition queues: one lock, multiple wait-sets.
await()/signal()replacewait()/notify()per-Condition, so a bounded buffer's not-full and not-empty predicates each get their own queue (no more waking everyone for one predicate).
var lock = new ReentrantLock();
var notEmpty = lock.newCondition();
// consumer: lock.lock(); try { while (empty) notEmpty.await(); ... } finally { lock.unlock(); }
// producer: lock.lock(); try { put(x); notEmpty.signal(); } finally { lock.unlock(); }
The rules that make it correct: await inside a loop (spurious wakeups are allowed), and unlock in finally (exceptions must not leak a held lock).