Skip to content
On this page

ReentrantLock

Since Java 5, the java.util.concurrent package was introduced to provide advanced concurrency handling, offering numerous features that greatly simplify the writing of multithreaded programs.

Java provides the synchronized keyword for locking, but this type of lock is heavyweight and requires threads to wait indefinitely when attempting to acquire it, without any additional retry mechanism.

The ReentrantLock class from the java.util.concurrent.locks package can be used as an alternative to synchronized. Let's look at the traditional synchronized code:

java
public class Counter {
    private int count;

    public void add(int n) {
        synchronized(this) {
            count += n;
        }
    }
}

If we replace it with ReentrantLock, the code can be refactored as follows:

java
public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count;

    public void add(int n) {
        lock.lock();
        try {
            count += n;
        } finally {
            lock.unlock();
        }
    }
}

Since synchronized is a language-level feature in Java, we do not need to handle exceptions explicitly. However, ReentrantLock is a lock implemented in Java code, so we must acquire the lock first and then release it properly in a finally block.

As the name suggests, ReentrantLock is a reentrant lock, meaning that a thread can acquire the same lock multiple times, just like with synchronized.

Unlike synchronized, ReentrantLock allows an attempt to acquire the lock:

java
if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        // Code to execute if the lock is acquired
    } finally {
        lock.unlock();
    }
}

In the code above, when attempting to acquire the lock, the maximum wait time is 1 second. If the lock is not acquired within 1 second, tryLock() returns false, allowing the program to perform additional handling rather than waiting indefinitely.

Therefore, using ReentrantLock is safer than using synchronized directly, as a failed tryLock() will not lead to a deadlock.

Summary

  • ReentrantLock can be used as an alternative to synchronized for synchronization.
  • Acquiring a lock with ReentrantLock is safer.
  • The lock must be acquired before entering the try {...} block, and a finally block should be used to ensure the lock is released.
  • tryLock() can be used to attempt to acquire the lock.
ReentrantLock has loaded