synchronized与Lock是互补而非替代关系:前者是JVM内置隐式锁,自动加解锁、安全简洁;后者是JDK显式锁,支持超时、中断、多条件队列等高级功能,适用于复杂并发场景。

实际上,synchronized 不能“替代”Lock 接口,而是两者是 Java 中实现线程同步的两种不同机制——synchronized 是语言内置的关键字,Lock 是 JDK 提供的接口(如 ReentrantLock)。它们不是替代关系,而是互补关系。更准确的问题是:什么时候该用 synchronized,什么时候该用 Lock?如何在实际中合理选择或迁移?
语法与使用方式差异明显
synchronized 是 JVM 层面支持的隐式锁,使用简单、自动加锁/解锁:
- 修饰实例方法:锁住当前对象(this)
- 修饰静态方法:锁住当前类的 Class 对象
- 修饰代码块:可指定任意对象作为锁,粒度更灵活
Lock(如 ReentrantLock)是显式锁,需要手动调用 lock() 和 unlock(),且必须在 finally 块中释放,否则易导致死锁:
- 支持公平/非公平策略
- 可尝试获取锁(tryLock)、可中断等待(lockInterruptibly)
- 支持多个条件队列(newCondition()),而 synchronized 只能配合一个 wait/notify
功能上 Lock 更强大,但 synchronized 更安全简洁
如果你只需要基本互斥,synchronized 几乎总是首选:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 不会忘记释放锁(JVM 自动保证)
- 与 JVM 优化深度集成(如锁消除、锁粗化、偏向锁)
- 代码更短,可读性高,出错率低
只有当需要以下能力时,才考虑 Lock:
- 超时获取锁(避免无限等待)
- 响应中断(比如线程被 cancel 时及时退出等待)
- 按条件精确唤醒(比如生产者只唤醒消费者,而不是 notifyAll)
- 实现非阻塞算法或复杂同步逻辑
常见误操作:不要强行用 synchronized “模拟” Lock 功能
例如,有人试图用 synchronized + wait/notify 实现 tryLock 效果,结果写出容易死锁或信号丢失的代码。这是反模式。
正确做法是:先明确需求 ——
- 要“等一会儿,不行就放弃”?→ 用 ReentrantLock.tryLock(long, TimeUnit)
- 要“被中断时立刻停止等待”?→ 用 lockInterruptibly()
- 只是保护一段临界区,无特殊要求?→ 优先用 synchronized
性能不是主要选型依据
在 JDK 1.6+,synchronized 经过大量优化,性能已接近甚至优于 ReentrantLock(尤其在无竞争或轻度竞争场景)。除非压测证明 Lock 在你的场景下有显著优势,否则不必为“听说 Lock 更快”而替换 synchronized。
真正影响性能的是锁粒度、持有时间、竞争强度,而不是 synchronized 还是 Lock。

















