Reentrant Lock

The ReentrantLock class implements the Lock interface. Instances of the Reentrant-Lock class are basically analogous to intrinsic locks. A thread needs to lock a ReentrantLock instance in order to gain exclusive access to a critical section guarded by the ReentrantLock instance. Afterward, the ReentrantLock instance must be unlocked so that other threads can try to gain access to the critical region.

The ReentrantLock class provides two constructors to create locks, with or without a fairness policy, as shown below at (1) and (2), respectively. The fairness policy is specified by the value true in the constructor. In this case, the acquisition order is that the longest-waiting thread for the lock is chosen to acquire the released lock. Otherwise, no guarantees are given as to how a thread will be chosen from the threads waiting to acquire the lock.

Click here to view code image

Lock frl = new ReentrantLock(true);  // (1) Fair reentrant lock
Lock rl = new ReentrantLock();       // (2) Reentrant lock with no fairness policy

ReentrantLock()

Creates an instance of ReentrantLock. This ReentrantLock instance does not use a fairness policy, and it is equivalent to ReentrantLock(false).

ReentrantLock(boolean fair)

Creates an instance of ReentrantLock with the given fairness policy. The fair ordering policy is implied by the value true, allowing the longest-waiting thread to acquire the lock when it is released.

The basic idiom to use a reentrant lock for mutual exclusion is shown below. A thread first locks the ReentrantLock instance at (1) by calling the lock() method—we say that the thread acquires the lock. At (2), the thread unlocks the ReentrantLock instance by calling the unlock() method—we say that the thread releases the lock. The thread has exclusive access to the code executed between (1) and (2) if it acquires the lock. Using the try-finally statement ensures that the lock is always released in the finally block. In general, the lock() and unlock() methods can be called in separate methods.

Click here to view code image

frl.lock();                // (1) Acquire the lock.
try {
  // Exclusive access…
} finally {
  frl.unlock();            // (2) Release the lock.
}

The ReentrantLock class implements methods of the Lock interface that define different lock acquisition policies.

  • Unconditional locking

The lock() method implements this policy, where the thread must unconditionally wait to acquire the lock if it is not available immediately.

Click here to view code image

frl.lock();                                              // Unconditional locking.
try { /* Lock acquired. Can access the resource. */ }
finally { frl.unlock(); }

  • Polled locking

The tryLock() method implements this policy, where the call will return immediately with the value false if the lock is not available. The value true is returned if the lock is acquired.

Click here to view code image

if (frl.tryLock()) {                                      // Polled locking.
  try { /* Lock acquired. Can access the resource. */ }
  finally { frl.unlock(); }
} else { /* Lock was not acquired. */ }

  • Timed locking

The tryLock(timeout, timeunit) method will also return false if the thread is not able to acquire the lock in the specified time. If the thread is interrupted while waiting for the lock, it will throw an InterruptedException.

Click here to view code image

try {
  if (frl.tryLock(100, TimeUnit.MILLISECONDS)) {           // Timed locking.
    try { /* Lock acquired. Can access the resource. */ }
    finally { frl.unlock(); }
  } else { /* Lock was not acquired. */ }
} catch (InterruptedException iex) { iex.printStackTrace(); }

  • Interruptible locking

The lockInterruptibly() method throws an InterruptedException if the thread is interrupted while acquiring the lock or while waiting for the lock.

Click here to view code image

try {
  frl.lockInterruptibly();                                // Interruptible locking.
  try { /* Lock acquired. Can access the resource. */ }
  finally { frl.unlock(); }
} catch (InterruptedException iex) { iex.printStackTrace(); }