Java synchronized和Lock区别 Java锁机制对比分析【详解】

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

synchronized 是 JVM 级别的内置锁

synchronized 是 Java 语言的关键字,由 JVM 直接支持,在字节码层面通过 monitorentermonitorexit 指令实现加锁与释放。它天然支持可重入,自动管理生命周期:只要线程执行完同步块或发生异常,锁就会被释放,无需手动干预。

它可以作用于三种场景:

  • 实例方法 → 锁对象是 this(当前实例)
  • 静态方法 → 锁对象是 类的 Class 对象
  • 同步代码块 → 锁对象是括号中指定的任意对象,推荐用私有 final 对象,避免外部干扰

它的锁默认是非公平的,不支持中断等待、超时获取、条件变量等高级控制,但写法简洁、不易出错,适合逻辑简单、竞争不激烈的场景。

Lock 是 AP

I 层面的显式锁接口

Lock 是 java.util.concurrent.locks 包中的接口,典型实现是 ReentrantLock。它不是语法糖,而是需要程序员显式调用 lock() 加锁、unlock() 释放锁——必须放在 finally 块中,否则可能造成死锁。

它提供的能力远超 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 的功能短板。