lock和synchronized区别
在 Java 中,synchronized 和 Lock(通常指 java.util.concurrent.locks.Lock 接口及其实现如 ReentrantLock)都是实现线程同步的重要手段,但它们在使用方式、底层机制、灵活性与性能方面存在明显差异。
一、基本概念对比
| 特性 | synchronized | Lock(如 ReentrantLock) |
|---|---|---|
| 所属包 | java 关键字(JVM 内建) | java.util.concurrent.locks 包 |
| 控制方式 | JVM 层面实现 | 基于 AQS(AbstractQueuedSynchronizer)实现 |
| 是否可重入 | ✅ 是 | ✅ 是(如 ReentrantLock) |
| 可否中断锁等待 | ❌ 不支持 | ✅ 支持(如 lockInterruptibly()) |
| 是否可尝试获取 | ❌ 不支持 | ✅ tryLock() 支持 |
| 是否可定时获取 | ❌ 不支持 | ✅ tryLock(long, TimeUnit) 支持 |
| 公平锁支持 | ❌ 不支持 | ✅ 支持(构造函数中传入 true) |
| 是否可绑定条件 | ❌ 不支持 | ✅ 支持 Condition 对象实现更细粒度控制 |
| 自动释放 | ✅ 是(自动释放锁) | ❌ 否(必须手动释放:unlock()) |
| 读写锁支持 | ❌ 不支持 | ✅ 支持(如 ReentrantReadWriteLock) |
| 性能(JDK 1.5+) | 中等 | 高(适用于竞争激烈场景) |
二、示例对比
示例 1️⃣:synchronized
public synchronized void doSomething() {
// 临界区
}
或使用同步块:
public void doSomething() {
synchronized(this) {
// 临界区
}
}
特点:
- 锁的是对象或类
- 进入和退出锁由 JVM 自动控制
示例 2️⃣:Lock(如 ReentrantLock)
private final ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock();
try {
// 临界区
} finally {
lock.unlock(); // 非常重要!否则会死锁
}
}
可用特性:
if (lock.tryLock(2, TimeUnit.SECONDS)) {
try {
// 成功加锁
} finally {
lock.unlock();
}
} else {
// 未能在 2 秒内获取锁
}
三、底层原理对比
| 特性 | synchronized | Lock |
|---|---|---|
| 实现机制 | JVM 内部 monitor(monitorenter / monitorexit) | 基于 AQS(AbstractQueuedSynchronizer) |
| 队列类型 | 内部不可见 | CLH 队列可控 |
| 阻塞/唤醒机制 | JVM Object.wait() / notify() | LockSupport.park() / unpark() |
| 可视化控制队列 | ❌ 不可控 | ✅ 可管理、可调试 |
四、适用场景
| 场景 | 推荐工具 |
|---|---|
| 简单同步场景(如同步方法) | synchronized ✅ |
| 需中断锁、定时锁尝试等高级控制 | Lock ✅ |
| 读多写少场景 | ReentrantReadWriteLock ✅ |
| 条件变量(如 await/signal) | Condition ✅ |
| 锁竞争激烈、性能要求高 | ReentrantLock ✅ |
五、Lock 特有功能(synchronized 做不到)
- 可中断加锁:
lockInterruptibly() - 定时加锁:
tryLock(timeout, unit) - 公平锁策略:避免饥饿(如
ReentrantLock(true)) - 多个条件变量支持:一个锁可配多个
Condition,更灵活 - 读写锁分离:如
ReentrantReadWriteLock提供读写分离锁
六、性能对比(现代 JVM)
- 在 低竞争场景,
synchronized和Lock差距不大 - 在 高并发、高冲突 场景下,
Lock表现更优(因为支持自旋、阻塞队列优化) - JDK 1.6+ 后引入了偏向锁、轻量级锁,synchronized 性能提升显著
七、总结建议
| 如果你想… | 建议使用 |
|---|---|
| 简单加锁控制、无需太多灵活性 | synchronized ✅ |
| 需要灵活地处理锁的获取、中断、定时、队列管理等 | Lock ✅ |
| 实现复杂同步器(如信号量、栅栏、屏障) | 自定义 AQS ✅ |
八、官方与权威资源推荐
- 🔗 ReentrantLock (Java SE 8 API)
- 🔗 synchronized (Java Language Spec)
- 🔗 JDK源码分析:AQS
- 美团技术博客:并发锁设计思路与优化实践
更多详细内容请关注其他相关文章!