JDK 1.6后两者性能基本持平,选择关键在于功能匹配:synchronized适合简单场景且自动释放安全;ReentrantLock适用于需中断等待、超时获取、公平锁或多Condition精准唤醒的复杂并发需求。

选 ReentrantLock 还是 synchronized,关键不在“哪个更好”,而在于“哪个更合适”。JDK 1.6 之后,两者性能已非常接近,拼的不再是速度,而是功能匹配度和工程可控性。
看是否需要中断等待
如果线程在等锁时必须能被外部中断(比如任务超时取消、服务优雅停机),synchronized 无能为力——它阻塞期间完全不响应 interrupt()。ReentrantLock 的 lockInterruptibly() 就是为此设计的:被中断会抛 InterruptedException,你可以捕获并清理资源、退出等待。
- 典型场景:定时任务调度器中,一个线程正在等锁执行关键操作,此时收到 shutdown 信号,需立即释放所有占用并退出
- 注意:synchronized 即使 catch 了 InterruptedException,也只是说明 wait() 被中断,跟“获取锁”本身无关
看是否要控制锁的获取行为
synchronized 只有一种模式:拿不到就死等。ReentrantLock 提供三种选择:
- lock():阻塞直到拿到(类似 synchronized)
- tryLock():立即返回 true/false,适合非阻塞探查
- tryLock(timeout, unit):最多等指定时间,超时自动放弃,避免无限挂起
例如数据库连接池分配连接时,若锁竞争激烈,用 tryLock(100, MILLISECONDS) 可防止线程长时间卡在锁上,转而走降级逻辑(如返回缓存值或快速失败)。
立即学习“Java免费学习笔记(深入)”;
看是否需要多条件精准唤醒
synchronized 只有一个 wait()/notify() 队列,notify() 是随机唤醒,notifyAll() 是全唤醒——容易造成“惊群”或误唤醒。ReentrantLock 配合 Condition 可创建多个独立等待队列:
- 生产者只 await notFull,消费者只 await notEmpty
- signal() 精准唤醒对应角色,没有干扰,吞吐更高
- 这是实现高性能生产者-消费者、读写分离等复杂协作模型的基础能力
看是否追求代码简洁与安全底线
synchronized 最大的优势是“不会漏解锁”:JVM 在字节码层面保证,无论正常结束还是抛异常,锁都会释放。ReentrantLock 必须手动 unlock(),且必须放在 finally 块里,否则一次异常就可能永久持锁,导致后续所有线程阻塞。
- 简单计数器、单次状态更新、短临界区——synchronized 更省心、更难出错
- 需要公平性(按请求顺序排队)、想监控锁状态(isLocked()、getHoldCount())、或跨方法加锁(比如 lock() 在 A 方法,unlock() 在 B 方法)——ReentrantLock 是唯一选择
不复杂但容易忽略:多数业务场景用 synchronized 完全够用;只有当明确需要可中断、超时、多条件、公平性这些特性时,才值得切换到 ReentrantLock,并承担手动管理锁的额外责任。


















