Fair locks in Java are a type of lock that ensures threads acquire the lock in the order they requested it, adhering to the first-come, first-served (FCFS) principle. This helps in preventing thread starvation, where certain threads might never acquire the lock due to continuous acquisition by other threads.
Using Fair Locks with ReentrantLock
The ReentrantLock class in Java provides an option to create a fair lock. By default, ReentrantLock is unfair, meaning it does not guarantee the order in which threads acquire the lock. However, by passing true to the constructor of ReentrantLock, you can create a fair lock.
Example of Fair Lock
Here’s an example demonstrating the use of a fair lock with ReentrantLock:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairLockExample {
private final Lock fairLock = new ReentrantLock(true); // Creating a fair lock
private int sharedResource = 0;
public void increment() {
fairLock.lock();
try {
sharedResource++;
System.out.println(Thread.currentThread().getName() + " incremented to: " + sharedResource);
} finally {
fairLock.unlock();
}
}
public static void main(String[] args) {
FairLockExample example = new FairLockExample();
// Creating multiple threads to test the fair lock
Runnable task = example::increment;
for (int i = 0; i < 5; i++) {
new Thread(task).start();
}
}
}
Explanation
- Creating the Lock:
TheReentrantLockis created with thefairparameter set totrue, ensuring that the lock is fair.
private final Lock fairLock = new ReentrantLock(true);
- Locking and Unlocking:
Theincrementmethod acquires the lock, increments the shared resource, prints the current thread name and the incremented value, and then releases the lock.
public void increment() {
fairLock.lock();
try {
sharedResource++;
System.out.println(Thread.currentThread().getName() + " incremented to: " + sharedResource);
} finally {
fairLock.unlock();
}
}
- Running the Example:
Multiple threads are created and started, each trying to increment the shared resource. Due to the fair lock, each thread will acquire the lock in the order they requested it, preventing thread starvation.
for (int i = 0; i < 5; i++) {
new Thread(task).start();
}
Benefits of Fair Locks
- Prevents Starvation:
- Fair locks ensure that all threads get a fair chance to acquire the lock, preventing some threads from being starved.
- Predictable Behavior:
- Fair locks provide more predictable behavior, especially in systems where it is crucial that every thread gets its turn without indefinite delay.
Performance Considerations
- Overhead:
- Fair locks typically have more overhead compared to unfair locks due to the additional bookkeeping needed to maintain the order of lock requests.
- Throughput:
- Unfair locks can provide higher throughput in some scenarios because they can allow more efficient context switching and lock acquisition.
Summary
Fair locks in Java, provided by ReentrantLock with the fairness parameter set to true, ensure that threads acquire locks in a first-come, first-served manner. This helps prevent thread starvation and provides more predictable behavior, at the cost of some performance overhead. Understanding when and how to use fair locks is crucial for building robust and fair multi-threaded applications.