Java ReentrantLock Example
In Java, ReentrantLock
is a synchronization mechanism provided by the java.util.concurrent.locks
package. It is an implementation of the Lock
interface that allows multiple threads to access a shared resource with exclusive or shared access. It is an alternative to the traditional synchronization provided by the synchronized
keyword.
ReentrantLock
offers the following key features:
- Locking and Unlocking: Threads can acquire the lock by calling the
lock()
method and release it using theunlock()
method. Only one thread can hold the lock at a time. - Reentrancy: A thread can acquire the lock multiple times, provided it releases the lock an equal number of times. This allows for nested critical sections within the same thread.
- Fairness:
ReentrantLock
can be configured to provide fairness in lock acquisition. When fairness is enabled, the lock favors the longest waiting thread to acquire the lock. - Condition Variables:
ReentrantLock
supports the use of condition variables, which allow threads to wait for specific conditions to be met before proceeding.
It is important to note that ReentrantLock
requires explicit lock acquisition and release, and it is the programmer’s responsibility to ensure proper usage to avoid potential issues such as deadlocks and race conditions.
Here’s an example that demonstrates the usage of ReentrantLock
in Java:
package org.websparrow;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private static final ReentrantLock lock = new ReentrantLock();
private static int counter = 0;
public static void main(String[] args) {
Thread thread1 = new Thread(ReentrantLockExample::incrementCounter);
Thread thread2 = new Thread(ReentrantLockExample::incrementCounter);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter);
}
private static void incrementCounter() {
lock.lock(); // Acquire the lock
try {
for (int i = 0; i < 1000; i++) {
counter++; // Critical section: Increment the counter
}
} finally {
lock.unlock(); // Release the lock
}
}
}
In this example, we have a shared variable counter
that needs to be incremented by multiple threads concurrently. We use a ReentrantLock
named lock
to ensure that only one thread can access the counter
variable at a time.
In the incrementCounter()
method, the lock.lock()
statement acquires the lock before entering the critical section, where the counter
is incremented in a loop. Once the loop is complete, the lock.unlock()
statement releases the lock, allowing other threads to acquire it.
By using the ReentrantLock
, we ensure that each thread increments the counter
safely without any race conditions. After both threads finish their execution, we print the final value of the counter
variable.