synchronized 是 JVM 内置锁,基于 monitorenter/monitorexit 指令实现,可重入、自动释放,支持实例方法、静态方法和同步代码块三种用法;Lock 是 API 显式锁,需手动加解锁,功能更丰富,支持公平性、超时、中断和 Condition。

synchronized 是 JVM 级别的内置锁
synchronized 是 Java 语言的关键字,由 JVM 直接支持,在字节码层面通过 monitorenter 和 monitorexit 指令实现加锁与释放。它天然支持可重入,自动管理生命周期:只要线程执行完同步块或发生异常,锁就会被释放,无需手动干预。
它可以作用于三种场景:
- 实例方法 → 锁对象是 this(当前实例)
- 静态方法 → 锁对象是 类的 Class 对象
- 同步代码块 → 锁对象是括号中指定的任意对象,推荐用私有 final 对象,避免外部干扰
它的锁默认是非公平的,不支持中断等待、超时获取、条件变量等高级控制,但写法简洁、不易出错,适合逻辑简单、竞争不激烈的场景。
Lock 是 API 层面的显式锁接口
Lock 是 java.util.concurrent.locks 包中的接口,典型实现是 ReentrantLock。它不是语法糖,而是需要程序员显式调用 lock() 加锁、unlock() 释放锁——必须放在 finally 块中,否则可能造成死锁。
立即学习“Java免费学习笔记(深入)”;
它提供的能力远超 synchronized:
- 可选择公平锁(构造时传
true)或非公平锁(默认) -
tryLock()实现非阻塞尝试获取锁,返回 boolean 判断是否成功 -
tryLock(long, TimeUnit)支持超时获取,避免无限等待 -
lockInterruptibly()让等待线程能响应 interrupt 信号 - 配合
Condition实现精准唤醒(比如只唤醒“生产者”或“消费者”),比wait/notify更灵活
底层机制和性能表现不同
synchronized 在 JDK 1.6+ 后引入了锁升级机制:偏向锁 → 轻量级锁 → 重量级锁,低竞争时开销极小;高竞争下会膨胀为操作系统互斥量,涉及用户态/内核态切换,代价升高。
Lock(如 ReentrantLock)基于 AQS(AbstractQueuedSynchronizer)实现,使用 CAS + 自旋 + 队列等待,全程在用户态完成,高并发下更可控、更稳定。虽然现代 JVM 优化后两者性能差距已不大,但在需精细调控的场景,Lock 仍具优势。
怎么选?看实际需求
优先用 synchronized 的情况:
- 同步逻辑短、简单,比如计数器增减、状态标记更新
- 不需要超时、中断、分组唤醒等扩展功能
- 团队编码规范强调简洁性和安全性,避免手动 unlock 遗漏
考虑用 Lock 的情况:
- 要实现可中断的等待(如任务取消时及时释放资源)
- 临界区执行时间不确定,需防止单一线程长期霸占锁
- 需要多个 Condition 配合(如读写锁分离、生产消费解耦)
- 压测发现 synchronized 在高争用下成为瓶颈,且确认 Lock 可改善
基本上就这些。不复杂但容易忽略——关键是别为了“高级”而用 Lock,也别因“简单”而硬扛 synchronized 的功能短板。










