synchronized是jvm内置关键字,隐式加解锁、异常安全;lock是api接口,需显式调用且必须try-finally保障释放,但支持中断、超时、条件变量等高级功能。

synchronized 和 Lock 都是用来保障多线程环境下共享资源安全访问的机制,但它们在设计定位、使用方式、控制粒度和适用场景上存在本质差异。选哪个不取决于“谁更好”,而在于“当前需求是否需要它提供的能力”。
实现层级与语法形式不同
synchronized 是 JVM 内置的关键字,属于语言级原语,编译后生成 monitorenter/monitorexit 字节码指令;Lock 是 java.util.concurrent.locks 包下的接口,需通过 ReentrantLock 等具体实现类显式调用 lock() / unlock() 方法。
- synchronized 可直接修饰方法或代码块,无需声明锁对象(静态方法锁 Class 对象,实例方法锁 this,代码块可指定任意对象)
- Lock 必须先创建一个锁实例(如 new ReentrantLock()),所有线程共用该实例,并手动控制加锁与释放时机
- synchronized 的加锁/解锁是隐式的、自动的;Lock 是显式的,必须配对使用,且强烈建议在 finally 块中 unlock(),否则异常时易导致死锁
异常处理与锁释放行为不同
synchronized 在发生任何异常时,JVM 保证自动释放锁,开发者无需干预;Lock 不具备这种保障 —— 若 lock() 成功后代码抛出异常且未执行 unlock(),锁将一直被持有,其他线程永久阻塞。
- 这是 Lock 使用中最容易出错的一点:必须写成 try-finally 结构,或使用 try-with-resources(配合自定义 CloseableLock 封装)
- synchronized 的“自动兜底”特性使其在简单同步场景下更安全、更简洁
功能扩展性与控制能力不同
Lock 提供了 synchronized 所不具备的高级能力,适用于需要精细控制并发逻辑的场景:
- 可中断等待:lockInterruptibly() 允许等待锁的线程响应 Thread.interrupt()
- 超时获取:tryLock(long, TimeUnit) 可设定最多等待多久,避免无限期挂起
- 非阻塞尝试:tryLock() 立即返回布尔值,便于实现轮询、重试或降级逻辑
- 条件队列分离:Lock.newCondition() 支持多个独立的 await()/signal() 条件变量,比 synchronized 的单一 wait()/notify() 更灵活
- 读写分离:ReentrantReadWriteLock 可区分读锁与写锁,提升读多写少场景的吞吐量
性能与 JVM 优化现状
早期(Java 5)Lock 性能明显优于 synchronized,因其基于 CAS 的乐观锁机制;但从 Java 6 起,JVM 对 synchronized 进行了大量优化(偏向锁、轻量级锁、锁消除、锁粗化等),在多数常见场景下二者性能已非常接近。
- 高竞争、复杂锁逻辑(如需中断、超时)时,Lock 仍具优势
- 简单同步块、方法级互斥、低竞争场景下,synchronized 更轻量、更不易出错
- 现代 JDK(如 17+)中,synchronized 已是官方推荐的首选,除非明确需要 Lock 的扩展功能
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











