← Concepts

阅读中文版本

Reentrant Locks

A reentrant lock can be acquired again by the thread that already holds it, incrementing a hold count — preventing self-deadlock when code paths legitimately re-enter guarded sections.

concurrency

Definition

Reentrancy lets the owning thread acquire the same lock multiple times, tracked by a hold counter released by matching unlock calls. Synchronized blocks in Java and critical sections in most threading libraries are reentrant. It prevents self-deadlock from nested calls into guarded methods at the cost of hiding accidental recursive locking that indicates design smell.

Context and scope

Default in Java synchronized and ReentrantLock, Python RLock, and C++ recursive_mutex. Contrast with non-reentrant designs where re-acquisition deadlocks immediately, exposing the recursion at once.

Common misconceptions

  • Reentrant locks prevent all deadlocks — they prevent only single-thread self-deadlock; multi-thread cycles remain fully possible
  • Reentrancy is free performance — hold counting adds overhead to every acquire and release
  • Recursive locking is a design smell that reentrancy merely silences — re-entrant paths through guarded code indicate the invariant should be split or the lock scope reduced

Anti-patterns

  • Building deep call chains through guarded public methods and leaning on reentrancy instead of restructuring
  • Acquiring in a loop and releasing once, corrupting the hold count
  • Assuming condition variables and reentrancy semantics compose the same across languages

Related concepts

Related examples

Authoritative source

https://en.wikipedia.org/wiki/Reentrant_mutex

What it is

A thread calls method A which takes the lock, then calls method B which takes the same lock. With a plain lock, the thread blocks on itself forever. A reentrant lock recognizes the owner and succeeds, counting depth until the matching releases unwind.

How it works

The lock records owner identity and a recursion counter; acquire by the owner increments, unlock decrements, and release-to-others happens at zero. Fairness, try-lock with timeout, and condition variables attach as features in library implementations like ReentrantLock.

When to use it

Public APIs whose guarded methods call each other, frameworks invoking user overrides inside locked regions, and compatibility with legacy call shapes. Prefer narrowing lock scope so reentrancy is unnecessary when the option exists.

Pitfalls

Reentrancy hides accidental recursion: performance degrades and invariants blur while the code keeps working. Mixing reentrancy with condition waits — a condition release during wait — surprises depth accounting. Self-deadlock removal buys nothing against two-thread cycles; lock ordering discipline still applies.