ReentrantLock in Java is part of the java.util.concurrent.locks package and provides a mechanism for thread synchronization similar to synchronized blocks/methods, but with more advanced features and capabilities. A ReentrantLock is so named because it allows threads to enter the lock on a resource more than once — hence, it’s “reentrant”.
Key Features of ReentrantLock
- Reentrant: A thread can hold the same lock multiple times. The lock keeps a count of the number of holds on it. When the count reaches zero, the lock is released.
- Interruptible Lock Acquisitions: Threads trying to acquire a lock can be interrupted. This is useful for preventing deadlock situations.
- Fairness: Optionally, the lock can be fair, meaning it grants access in a first-come, first-served order, if constructed with the
fairflag set totrue. - Lock Polling and Timed Locks: Provides methods to acquire a lock with a timeout (
tryLock()), allowing threads to wait for a lock for a certain period before giving up. - Condition Support: Supports
Conditionobjects, which allow threads to wait for certain conditions to be met while the lock is held, similar to theObject.wait()andnotify()methods in synchronized blocks.
Basic Usage Example
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock(); // Acquire the lock
try {
count++;
} finally {
lock.unlock(); // Always ensure to unlock in finally block
}
}
public int getCount() {
return count;
}
public static void main(String[] args) {
Counter counter = new Counter();
// Example usage in threads
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Count: " + counter.getCount());
}
}
In this example, ReentrantLock is used to ensure that only one thread can execute the increment method at a time, thus avoiding concurrent modification issues.
When to Use ReentrantLock
- Advanced Synchronization: Use
ReentrantLockwhen you need advanced synchronization features that are not available with synchronized blocks/methods. - Fine-Grained Control: It offers more control, such as the ability to try to acquire a lock without waiting forever, and to interrupt a thread waiting to acquire a lock.
- Fairness Policy: When you need a fairness policy for thread scheduling.
Conclusion
ReentrantLock is a powerful tool for controlling access to shared resources in multi-threaded environments. However, it’s more complex than synchronized blocks and should be used when its advanced features are required. Always remember to unlock in a finally block to ensure that locks are released even if an exception occurs.
