锁机制(ReentrantLock 等)
Lock 接口位于 java.util.concurrent.locks 包,提供灵活的锁机制。
Lock 接口方法
Java
public interface Lock {
void lock(); // 获取锁
void lockInterruptibly(); // 可中断获取锁
boolean tryLock(); // 尝试获取,立即返回
boolean tryLock(long time, TimeUnit unit); // 超时尝试
void unlock(); // 释放锁
Condition newCondition(); // 创建条件变量
}
ReentrantLock 基本用法
Java
private final ReentrantLock lock = new ReentrantLock();
public void method() {
lock.lock(); // 获取锁
try {
// 同步代码
} finally {
lock.unlock(); // 必须在 finally 中释放
}
}
必须在 finally 中 unlock:避免异常导致锁未释放,造成死锁。
ReentrantLock 特性
公平锁与非公平锁
Java
// 非公平锁(默认,性能更高)
ReentrantLock unfairLock = new ReentrantLock();
// 公平锁(按等待顺序获取)
ReentrantLock fairLock = new ReentrantLock(true);
| 类型 | 特点 |
|---|---|
| 非公平锁 | 性能高,可能饥饿 |
| 公平锁 | 按顺序获取,性能略低 |
可中断锁
Java
try {
lock.lockInterruptibly(); // 可被 interrupt() 中断等待
// 同步代码
} catch (InterruptedException e) {
// 处理中断
} finally {
lock.unlock();
}
synchronized 不支持中断:ReentrantLock 可中断等待。
超时获取锁
Java
if (lock.tryLock(3, TimeUnit.SECONDS)) { // 等待 3 秒
try {
// 获取成功,执行同步代码
} finally {
lock.unlock();
}
} else {
// 获取失败,执行其他逻辑
}
避免无限等待:tryLock(timeout) 设置超时,失败执行降级逻辑。
Condition 条件变量
Java
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
// 等待
public void await() throws InterruptedException {
lock.lock();
try {
while (!conditionMet) {
condition.await(); // 等待条件
}
// 条件满足后执行
} finally {
lock.unlock();
}
}
// 唤醒
public void signal() {
lock.lock();
try {
conditionMet = true;
condition.signal(); // 唤醒一个等待线程
condition.signalAll(); // 唤醒所有等待线程
} finally {
lock.unlock();
}
}
多条件变量
Java
ReentrantLock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
// 精确控制不同条件的等待和唤醒
ReentrantReadWriteLock
读写锁,读锁共享,写锁独占:
Java
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock(); // 读锁(共享)
Lock writeLock = rwLock.writeLock(); // 写锁(独占)
// 读操作
public int read() {
readLock.lock();
try {
return value; // 多线程可同时读
} finally {
readLock.unlock();
}
}
// 写操作
public void write(int newValue) {
writeLock.lock();
try {
value = newValue; // 写时禁止其他读写
} finally {
writeLock.unlock();
}
}
读写锁适用:读多写少场景,如缓存、配置。
StampedLock
乐观读锁,性能更高(JDK 8):
Java
StampedLock lock = new StampedLock();
// 写锁
long stamp = lock.writeLock();
try {
value = newValue;
} finally {
lock.unlockWrite(stamp);
}
// 读锁
long stamp = lock.readLock();
try {
return value;
} finally {
lock.unlockRead(stamp);
}
// 乐观读(无锁)
long stamp = lock.tryOptimisticRead();
int v = value;
if (!lock.validate(stamp)) { // 验证是否有写操作
stamp = lock.readLock(); // 有写操作,转为读锁
try {
v = value;
} finally {
lock.unlockRead(stamp);
}
}
return v;
ReentrantLock vs synchronized
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 获取释放 | 自动 | 手动 unlock |
| 公平锁 | ❌ 非公平 | ✅ 可选公平 |
| 可中断 | ❌ | ✅ lockInterruptibly |
| 超时获取 | ❌ | ✅ tryLock(timeout) |
| 条件变量 | 单个 | 多个 Condition |
| 性能 | JDK 6 后差距小 | 略有优势 |
选择原则:优先 synchronized,需要公平锁/可中断/超时/多条件时用 ReentrantLock。
要点总结
- Lock 接口比 synchronized 功能更灵活
- ReentrantLock 必须在 finally 中 unlock
- 支持公平锁/非公平锁,默认非公平
- lockInterruptibly() 可中断等待
- tryLock(timeout) 超时获取,避免无限等待
- Condition 支持多条件变量,精确唤醒
- ReentrantReadWriteLock:读锁共享,写锁独占
- StampedLock:乐观读,性能最高
- 优先 synchronized,高级需求用 ReentrantLock
📝 发现内容有误?点击此处直接编辑