Skip to main content
๐Ÿ“œ WAYPOINT LESSON

ReentrantLock and Condition queues

โญโญโญ advancedโณ 17 min read๐Ÿ“ Lesson 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 โ€” synchronized cannot.
  • Condition queues: one lock, multiple wait-sets. await()/signal() replace wait()/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).