ReentrantLock like its name suggests, is reentrant; Allowing the same thread to acquire the same lock multiple times!

Fairness

When a thread fails to acquire the lock, it goes into the waiting state and joins the Entry/Sync Queue of the lock. This Sync Queue is implemented with AbstractQueuedSynchronizer, so it guarantees FIFO ordering.
Yet, the constructor still has an optional fairness parameter which is set to false by default:

  • unfair: new ReentrantLock() or new ReentrantLock(false)
  • fair: new ReentrantLock(true)

Even though the Sync Queue is already FIFO ordered which would mean that it is intrinsically fair, the default “unfair” mode, allows for “barging”.

Barging is when a running thread skips ahead of the waiting threads in the Sync Queue and acquires the lock. Barging is possible in “unfair” mode because ReentrantLock doesn’t check if there are threads in the Sync Queue before issuing the lock.
Whereas when initialised to be “fair”, the ReentrantLock checks the Sync Queue before issuing the lock, preventing barging.

Enabling fairness helps to reduce the probability of thread starvation but comes with a slight performance penalty.

It doesn’t completely prevent thread starvation because ultimately that depends on the OS thread scheduler. If the scheduler starves a thread before it can attempt to acquire a lock, theres nothing that lock ordering can do to prevent starvation.

An important caveat, is that the tryLock() method is explicitly allowed to barge in both the fair and unfair implementations of AbstractQueuedSynchronizer in the ReentrantLock.

Multiple Condition Queues

ReentrantLock supports multiple “wait queues” via the Condition interface (similar to wait/notify but more flexible).
Fairness only applies within each queue, not between queues.

Intra-queue fairness: yes! (within a single condition queue)
Inter-queue fairness: no! (between different condition queues)

Thread States

Built on AbstractQueuedSynchronizer (AQS) using park/unpark mechanisms.
Threads waiting for locks are in WAITING or TIMED_WAITING states (NEVER BLOCKED).