在Java多线程编程中,当多个线程需要操作同一份共享资源时,为了避免出现数据不一致、竞态条件等问题,需要使用锁机制对资源访问进行控制。ReentrantLock是java.util.concurrent.locks包下提供的可重入锁实现,相比传统的synchronized关键字,它提供了更灵活的锁操作方式,其中就包括公平锁模式的配置。

ReentrantLock公平锁的基本概念
公平锁指的是当多个线程等待获取锁时,锁的分配会严格按照线程进入等待队列的先后顺序进行,先到等待队列的线程会优先获得锁资源,不会出现后请求的线程先拿到锁的情况。ReentrantLock默认创建的是非公平锁,要实现公平锁,只需要在创建ReentrantLock实例时传入true参数即可。
ReentrantLock实现公平锁的基础用法
实现公平锁的核心是在构造ReentrantLock时指定公平策略,之后通过lock()方法获取锁,unlock()方法释放锁,通常把释放锁的操作放在finally代码块中,避免锁无法释放导致死锁。
下面是一个简单的公平锁使用示例,模拟多个线程按顺序获取锁并操作共享资源:
import java.util.concurrent.locks.ReentrantLock;
public class FairLockDemo {
// 创建公平锁,构造参数传入true表示启用公平模式
private static final ReentrantLock fairLock = new ReentrantLock(true);
private static int sharedCount = 0;
static class WorkerThread extends Thread {
private final String threadName;
public WorkerThread(String name) {
this.threadName = name;
}
@Override
public void run() {
// 获取公平锁
fairLock.lock();
try {
// 操作共享资源
sharedCount++;
System.out.println(threadName + " 获取到锁,当前共享计数:" + sharedCount);
// 模拟业务处理耗时
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 释放锁,必须放在finally中保证锁一定会被释放
fairLock.unlock();
System.out.println(threadName + " 释放了锁");
}
}
}
public static void main(String[] args) {
// 创建5个线程按顺序启动
for (int i = 1; i <= 5; i++) {
new WorkerThread("线程" + i).start();
}
}
}
运行上述代码后,可以看到线程获取锁的顺序和线程启动的顺序基本一致,不会出现后启动的线程先拿到锁的情况,这就是公平锁的作用效果。
公平锁与非公平锁的差异对比
ReentrantLock的公平锁和非公平锁在性能和使用场景上有明显区别,具体对比如下:
| 对比维度 | 公平锁 | 非公平锁 |
|---|---|---|
| 锁分配规则 | 严格按照线程等待队列顺序分配 | 线程可以先尝试直接获取锁,获取失败再进入等待队列 |
| 线程饥饿问题 | 不会出现,所有线程都能按顺序获取锁 | 可能出现,等待时间长的线程可能一直拿不到锁 |
| 性能表现 | 较低,需要维护等待队列顺序,线程切换开销大 | 较高,减少了线程切换次数,吞吐量更大 |
| 适用场景 | 需要严格保证线程获取锁顺序的场景 | 大部分对顺序无要求的普通多线程场景 |
公平锁使用注意事项
- 公平锁的性能比非公平锁低,因为每次获取锁都需要检查等待队列,会增加线程上下文切换的开销,如果不是必须保证获取顺序,优先使用非公平锁。
- 公平锁只保证获取锁的顺序,不保证线程启动的顺序,因为线程启动后进入等待队列的时间可能受系统调度影响。
- 使用ReentrantLock时必须保证
unlock()方法一定会被执行,否则会导致锁泄漏,其他线程永远无法获取该锁。 - 如果需要在等待锁的过程中响应中断,可以使用
lockInterruptibly()方法替代lock()方法获取锁。
公平锁在多线程访问控制中的应用
公平锁适合用在对资源访问顺序有严格要求的场景,比如需要按照请求顺序处理任务的队列系统,或者需要保证先提交的任务先获得资源执行权的业务场景。在这些场景中,使用公平锁可以避免后提交的请求抢占资源,保证业务处理的公平性。
下面是一个简单的任务处理示例,使用公平锁保证任务按提交顺序执行:
import java.util.concurrent.locks.ReentrantLock;
public class TaskProcessDemo {
private static final ReentrantLock fairLock = new ReentrantLock(true);
// 任务处理方法
public static void processTask(String taskId) {
fairLock.lock();
try {
System.out.println("开始处理任务:" + taskId);
// 模拟任务处理耗时
Thread.sleep(200);
System.out.println("任务" + taskId + "处理完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
fairLock.unlock();
}
}
public static void main(String[] args) {
// 模拟按顺序提交任务
for (int i = 1; i <= 3; i++) {
final String taskId = "TASK_" + i;
new Thread(() -> processTask(taskId), "提交线程" + i).start();
}
}
}
通过上述示例可以看到,任务会按照提交的顺序依次被处理,不会出现后提交的任务先完成的情况,满足了多线程访问控制中的公平性要求。
ReentrantLock公平锁Java多线程访问控制修改时间:2026-07-03 07:21:24