ReentrantLock 的 lock() 和 tryLock() 方法区别
·
文章目录
1. 方法签名和行为对比
// lock() 方法:阻塞式获取锁
public void lock() {
sync.lock(); // 调用AQS的acquire(1)方法
}
// tryLock() 方法:非阻塞式尝试获取锁
public boolean tryLock() {
return sync.nonfairTryAcquire(1); // 尝试获取,不阻塞
}
// tryLock(long timeout, TimeUnit unit) 方法:带超时的尝试获取锁
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
2. 核心区别
| 特性 | lock() | tryLock() |
|---|---|---|
| 阻塞行为 | 阻塞当前线程,直到获得锁 | 不阻塞,立即返回 |
| 返回值 | 无返回值(void) | 返回boolean值(true/false) |
| 超时控制 | 无超时 | 可选超时(tryLock(long, TimeUnit)) |
| 异常抛出 | 无异常 | 无异常(失败返回false) |
3. 详细实现对比
lock() 方法实现:
public void lock() {
sync.lock(); // AQS中的acquire(1)方法
// acquire(1)内部逻辑:
// 1. 尝试CAS设置状态(非阻塞)
// 2. 如果失败,进入队列等待
// 3. 等待被唤醒后重新尝试获取锁
}
tryLock() 方法实现:
public boolean tryLock() {
return sync.nonfairTryAcquire(1); // 底层基于AQS中的compareAndSetState方法
// nonfairTryAcquire内部逻辑:
// 1. 尝试CAS设置状态(非阻塞)
// 2. 成功则返回true
// 3. 失败则返回false(不阻塞)
}
4. 实际使用场景
lock() 使用示例:
ReentrantLock lock = new ReentrantLock();
lock.lock(); // 阻塞直到获得锁
try {
// 执行临界区代码
} finally {
lock.unlock();
}
tryLock() 使用示例:
ReentrantLock lock = new ReentrantLock();
if (lock.tryLock()) { // 尝试获取锁
try {
// 执行临界区代码
} finally {
lock.unlock(); // 必须解锁
}
} else {
// 锁已被其他线程持有,继续执行其他逻辑
System.out.println("锁不可用,执行其他任务");
}
5. 性能和适用场景
lock() 适合:
- 必须获得锁:业务逻辑依赖锁资源
- 高竞争环境:锁可能长时间被占用
- 同步语义明确:需要保证原子性操作
tryLock() 适合:
- 可选锁:锁不是必需的
- 高并发环境:避免长时间阻塞
- 重入锁:需要多次尝试获取锁
- 组合策略:与其他条件判断结合使用
6. 注意事项
tryLock() 的潜在问题:
// 错误示例:忘记检查返回值
if (lock.tryLock()) { // 正确,检查返回值
// 执行临界区
} else {
// 处理锁不可用的情况
}
// 错误示例:忽略tryLock()返回值
lock.tryLock(); // 错误,没有检查是否成功获取锁
// 如果锁不可用,会立即返回false,但程序继续执行
lock() 的潜在问题:
// 错误示例:忘记unlock()
lock.lock();
// 执行临界区
// 忘记unlock() → 导致死锁或资源泄漏!
// 正确做法:使用try-finally确保解锁
lock.lock();
try {
// 执行临界区
} finally {
lock.unlock(); // 保证总是解锁
}
7. 完整对比示例
public class LockComparisonExample {
private final ReentrantLock lock = new ReentrantLock();
public void methodWithLock() {
lock.lock(); // 阻塞直到获得锁
try {
// 执行临界区代码
System.out.println(Thread.currentThread().getName() + " 获取锁");
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock(); // 释放锁
}
}
public void methodWithTryLock() {
if (lock.tryLock()) { // 尝试获取锁
try {
// 执行临界区代码
System.out.println(Thread.currentThread().getName() + " 获取锁");
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock(); // 释放锁
}
} else {
// 锁不可用,执行其他逻辑
System.out.println(Thread.currentThread().getName() + " 锁不可用");
}
}
}
8. 总结
| 对比维度 | lock() | tryLock() |
|---|---|---|
| 阻塞性 | 阻塞当前线程 | 不阻塞,立即返回 |
| 返回值 | void | boolean |
| 超时控制 | 无 | 可选超时(tryLock(long, TimeUnit)) |
| 适用场景 | 必须获得锁 | 可选锁、高并发、避免阻塞 |
| 错误处理 | 必须在finally中解锁 | 必须检查返回值 |
简单记忆:
lock()就像排队等车,必须等到有座位才走tryLock()就像问"有没有空位",有就坐,没有就继续干别的
如果锁是必需品,用lock();
如果锁可以等待或不需要,用tryLock()。
更多推荐


所有评论(0)