一、可中断锁
1. 核心方法:lockInterruptibly()
- 作用:允许线程在等待锁的过程中响应中断请求。
- 适用场景:需要支持任务取消或中断的同步操作(如用户手动取消长时间等待的任务)。
2. 代码示例
ReentrantLock lock = new ReentrantLock();
Thread thread = new Thread(() -> {
try {
lock.lockInterruptibly(); // 可中断获取锁
try {
System.out.println("线程获取锁并执行任务");
Thread.sleep(5000); // 模拟耗时操作
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
System.out.println("线程被中断,放弃获取锁");
}
});
lock.lock(); // 主线程先获取锁
try {
thread.start();
Thread.sleep(1000); // 确保子线程开始等待锁
thread.interrupt(); // 中断子线程
} finally {
lock.unlock();
}
3. 行为分析
- 未中断时:线程正常获取锁并执行任务。
- 中断时:抛出
InterruptedException
,线程退出等待队列。
二、锁超时
1. 核心方法:tryLock()
-
无参方法:
boolean tryLock()
立即尝试获取锁,成功返回true
,失败返回false
。 -
带超时方法:
boolean tryLock(long timeout, TimeUnit unit)
在指定时间内尝试获取锁,超时后放弃。
2. 代码示例:避免死锁
ReentrantLock lockA = new ReentrantLock();
ReentrantLock lockB = new ReentrantLock();
Thread thread1 = new Thread(() -> {
try {
if (lockA.tryLock(1, TimeUnit.SECONDS)) { // 尝试获取lockA
try {
if (lockB.tryLock(1, TimeUnit.SECONDS)) { // 尝试获取lockB
System.out.println("Thread1完成任务");
}
} finally {
if (lockB.isHeldByCurrentThread()) lockB.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lockA.isHeldByCurrentThread()) lockA.unlock();
}
});
Thread thread2 = new Thread(() -> { /* 类似逻辑,先尝试lockB再lockA */ });
thread1.start();
thread2.start();
3. 应用场景
- 死锁预防:通过超时放弃锁请求,打破循环等待。
- 响应性优化:避免线程长时间阻塞影响系统响应速度。
三、条件变量
1. 核心机制
- 创建条件变量:
Condition condition = lock.newCondition();
- 等待条件:
condition.await();
- 唤醒线程:
condition.signal()
或condition.signalAll()
2. 代码示例:生产者-消费者模型
ReentrantLock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition(); // 非空条件
Condition notFull = lock.newCondition(); // 非满条件
Queue<Integer> queue = new LinkedList<>();
int maxSize = 10;
// 生产者
new Thread(() -> {
lock.lock();
try {
while (queue.size() == maxSize) {
notFull.await(); // 等待队列非满
}
queue.add(1);
notEmpty.signal(); // 通知消费者
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
// 消费者
new Thread(() -> {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await(); // 等待队列非空
}
queue.poll();
notFull.signal(); // 通知生产者
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
3. 优势对比 wait()/notify()
特性 | Condition | wait()/notify() |
---|---|---|
多条件支持 | ✅ 可创建多个条件变量 | ❌ 每个对象仅一个等待队列 |
精准唤醒 | ✅ signal() 唤醒指定条件队列的线程 | ❌ notify() 随机唤醒 |
四、关键注意事项
1. 锁释放
- 必须手动释放:
lock.unlock()
需放在finally
块中确保执行。 - 重入次数匹配:加锁和解锁次数必须一致,否则导致锁无法释放。
2. 中断处理
- 响应中断:
lockInterruptibly()
和await()
需捕获InterruptedException
。 - 恢复中断状态:调用
Thread.currentThread().interrupt()
保留中断标志。