In Java, a Reentrant Lock is part of the java.util.concurrent.locks package and provides a more flexible mechanism for thread synchronization compared to the synchronized keyword. It allows threads to enter a lock multiple times (reentrant behavior) without causing deadlock on itself. It offers features like:
- Reentrancy: The same thread can acquire the lock multiple times. Each lock acquisition must be paired with a corresponding unlock.
- Explicit Locking: Unlike synchronized, Reentrant Lock requires manual locking and unlocking using lock() and unlock().
- Interruptible: Threads waiting for a lock can be interrupted.
- TryLock() Support: Threads can attempt to acquire a lock without waiting indefinitely.
- Fairness Policy: Locks can be configured to grant access in first-come-first-serve order.
Declaration and Usage
Reentrant locks are created using the ReentrantLock class:
Java
import java.util.concurrent.locks.ReentrantLock;
public class SharedResource {
private final ReentrantLock lock = new ReentrantLock();
public void performTask() {
lock.lock(); // Acquire lock
try {
// Critical section code
System.out.println(Thread.currentThread().getName() + " is performing task");
} finally {
lock.unlock(); // Release lock
}
}
}
Explanation:
- lock.lock() acquires the lock. If another thread holds it, the current thread waits.
- The critical section contains code that must be accessed by only one thread at a time.
- lock.unlock() releases the lock in the finally block to ensure it is released even if an exception occurs.
Reentrant Behavior Example
Java
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantExample {
private final ReentrantLock lock = new ReentrantLock();
public void methodA() {
lock.lock();
try {
System.out.println("Inside Method A");
methodB(); // Reentrant lock allows the same thread to enter methodB
} finally {
lock.unlock();
}
}
public void methodB() {
lock.lock();
try {
System.out.println("Inside Method B");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantExample example = new ReentrantExample();
example.methodA();
}
}
OutputInside Method A
Inside Method B
Here, the same thread acquires the lock twice without any issue, demonstrating reentrant behavior.
Fairness Policy
Reentrant locks can be created with a fairness option:
Java
ReentrantLock fairLock = new ReentrantLock(true); // Fair lock
- Fair lock: Threads acquire the lock in the order they requested it (first-come-first-serve).
- Non-fair lock (default): Threads may acquire the lock in an arbitrary order, which can improve throughput but may cause starvation.
ReentrantLock() Methods
| Method | Description |
|---|
| lock() | Acquires the lock, incrementing the hold count. If the resource is free, the current thread gets it. |
|---|
| unlock() | Releases the lock, decrementing the hold count. When the count reaches zero, the resource is released. |
|---|
| tryLock() | Attempts to acquire the lock without blocking. Returns true if successful, false if busy. |
|---|
| tryLock(long timeout, TimeUnit unit) | Waits up to the specified time to acquire the lock, then exits if unsuccessful. |
|---|
| lockInterruptibly() | Acquires the lock unless the thread is interrupted while waiting. |
|---|
| getHoldCount() | Returns the number of times the current thread holds the lock. |
|---|
| isHeldByCurrentThread() | Returns true if the current thread holds the lock. |
|---|
| hasQueuedThreads() | Checks if there are threads waiting to acquire the lock. |
|---|
| isLocked() | Returns true if any thread holds the lock. |
|---|
| newCondition() | Returns a Condition instance associated with this lock for advanced thread coordination. |
|---|
Advantages over synchronized
| Feature | synchronized | ReentrantLock |
|---|
| Lock acquisition | Implicit | Explicit (lock() and unlock()) |
|---|
| Interruptible | No | Yes |
|---|
| Try-lock | No | Yes (tryLock()) |
|---|
| Fairness | No | Optional |
|---|
| Reentrant | Yes | Yes |
|---|
Explore
Java Basics
OOP & Interfaces
Collections
Exception Handling
Java Advanced
Practice Java