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
My Profile