reentrantlock 通过公平锁、分段加锁、condition 背压及严格锁生命周期管理,提升流水线并发健壮性与吞吐量。

ReentrantLock 本身不直接构建流水线,但它能为流水线各阶段提供比 synchronized 更精细的线程控制能力——关键在于用它保护共享状态、协调阶段间依赖,并配合 Condition 实现精准唤醒。高健壮性体现在:避免死锁、支持中断、可超时获取锁、明确锁边界、便于监控与诊断。
用公平锁 + 可中断获取,防止饥饿与无限等待
流水线中若某阶段长期被抢占(如 IO 延迟),非公平锁可能导致后续任务持续“插队”,造成某些任务饿死。启用公平模式并使用 lockInterruptibly(),让等待线程响应中断,便于外部主动终止卡住的任务:
private final ReentrantLock stageLock = new ReentrantLock(true); // 公平锁
private final Condition notEmpty = stageLock.newCondition();
public void submit(Task task) throws InterruptedException {
stageLock.lockInterruptibly(); // 可中断,不阻塞在锁上
try {
queue.add(task);
notEmpty.signal(); // 唤醒消费者
} finally {
stageLock.unlock();
}
}
分段加锁 + 锁分离,提升吞吐并降低锁竞争
典型流水线含多个阶段(如解析 → 校验 → 转换 → 存储),若所有阶段共用一把锁,会形成串行瓶颈。应为每个阶段独立建锁,甚至对读写操作进一步分离(如用读写锁保护缓存):
- 每个 Stage 封装自己的
ReentrantLock,仅保护本阶段内部状态(如本地队列、计数器) - 阶段间通信通过无锁队列(如
LinkedBlockingQueue)或带条件的锁队列,避免跨阶段持锁 - 若某阶段需高频读缓存、偶发写,改用
ReentrantReadWriteLock,读不互斥
结合 Condition 精确控制阶段启停与背压
当下游阶段处理变慢(如数据库写入延迟),需让上游减速,避免内存溢出。用 Condition 实现有界缓冲区的“满则等待”逻辑,比简单 while-loop + sleep 更高效、更可控:
private final ReentrantLock bufferLock = new ReentrantLock();
private final Condition bufferFull = bufferLock.newCondition();
private final Condition bufferEmpty = bufferLock.newCondition();
private final List<task> buffer = new ArrayList();
private final int capacity = 100;
public void put(Task task) throws InterruptedException {
bufferLock.lock();
try {
while (buffer.size() >= capacity) {
bufferFull.await(); // 等待空间释放,响应中断
}
buffer.add(task);
bufferEmpty.signal(); // 通知消费者有新任务
} finally {
bufferLock.unlock();
}
}
public Task take() throws InterruptedException {
bufferLock.lock();
try {
while (buffer.isEmpty()) {
bufferEmpty.await();
}
Task task = buffer.remove(0);
bufferFull.signal(); // 通知生产者可继续提交
return task;
} finally {
bufferLock.unlock();
}
}
</task>
锁的生命周期必须严格匹配业务边界,杜绝嵌套与泄漏
健壮性隐患常来自锁未正确释放或在异常路径中遗漏 unlock。务必遵循“lock → try → finally → unlock”结构;禁用在锁内调用不可控的第三方方法(如远程调用、复杂回调),以防锁持有时间失控:
- 所有
lock()必须配对unlock(),且只能在finally块中执行 - 避免在锁内做 IO、网络、长时间计算;耗时操作应复制数据后解锁再执行
- 启用
ReentrantLock.getHoldCount()或 JMX 暴露锁状态,用于线上问题排查 - 必要时使用
tryLock(long, TimeUnit)设定最大等待时间,失败即退避或降级
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











