reentrantlock需用lockinterruptibly()响应中断,公平锁性能低2–5倍且不绝对保序,unlock()须在finally中配对调用并校验持有状态,condition支持多等待队列实现精准唤醒。

ReentrantLock响应中断:为什么lock()不行,必须用lockInterruptibly()
调用 lock() 会无视线程中断,哪怕你已调用 Thread.interrupt(),它仍会一直阻塞直到获取锁;只有 lockInterruptibly() 才会在等待锁期间响应中断,并抛出 InterruptedException。
典型场景是带超时或需协作取消的长任务,比如后台作业被用户主动终止、服务优雅停机。
- 必须在
try块外捕获InterruptedException,否则中断状态会被吞掉 - 捕获后通常要恢复中断状态:
Thread.currentThread().interrupt(); - 不要在持有锁时才去检查中断——得在等待阶段就响应,否则失去意义
try {
lock.lockInterruptibly(); // ← 这里会响应中断
// 临界区操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断标记
throw new RuntimeException("被中断,放弃获取锁", e);
} finally {
if (lock.isHeldByCurrentThread()) lock.unlock();
}
公平锁开启后性能明显下降:不是所有场景都该设true
ReentrantLock 构造函数传 true 启用公平模式,意味着新请求锁的线程必须排队,不能插队;但代价是每次加锁都要遍历同步队列,吞吐量通常比非公平锁低 2–5 倍。
真实项目中,除非业务逻辑明确依赖“先到先得”(如资源分配需严格顺序、避免饥饿),否则默认用非公平锁更合理。
立即学习“Java免费学习笔记(深入)”;
- 公平锁不保证“绝对时间顺序”,只按入队顺序,而线程调度本身有延迟
- 高并发下,公平锁更容易引发大量线程阻塞和上下文切换
-
isFair()返回true仅表示构造时设了公平,不反映当前是否真在排队
unlock() 必须配对调用,且只能由持有锁的线程执行
unlock() 不做线程校验——如果由非持有线程调用,会直接抛 IllegalMonitorStateException;漏调或重复调用都会破坏锁状态,导致死锁或 IllegalStateException。
最稳妥写法是把 unlock() 放进 finally 块,且加一层 isHeldByCurrentThread() 防御性判断。
- 别依赖 try-with-resources 自动释放——
ReentrantLock不实现AutoCloseable - 嵌套锁场景下,每次
lock()对应一次unlock(),重入次数必须匹配 - 日志或监控中发现
IllegalMonitorStateException,优先查unlock()是否错放位置或条件分支遗漏
Condition.await() 和 Object.wait() 的关键区别在哪
Condition 是 ReentrantLock 的配套等待机制,和 Object.wait() 不兼容——不能在 synchronized 块里调 condition.await(),也不能在 lock() 里调 obj.wait()。
真正优势在于一个锁可绑定多个 Condition 实例,实现精准唤醒(比如生产者只唤醒消费者,不惊动其他等待线程)。
-
await()会自动释放锁,并在被signal()后重新竞争锁,不是“直接继续执行” -
signalAll()不等于广播——它只是把所有等待线程移入 AQS 同步队列,谁先抢到锁仍不确定 - 用
Condition时,await()前必须已持有对应锁,否则抛IllegalMonitorStateException










