synchronized与Lock深度对比
Java并发编程:synchronized与Lock深度对比
- 基本概念
1.1 synchronized
synchronized
是Java内置的关键字,属于JVM层面的锁机制。它通过对象监视器(Monitor)实现同步,具有自动获取和释放锁的特性。
// 同步方法
public synchronized void syncMethod() {// 代码
}// 同步代码块
public void method() {synchronized(this) {// 代码}
}
1.2 Lock
Lock
是Java并发包(java.util.concurrent.locks)提供的接口,属于API层面的锁机制。最常用的实现类是ReentrantLock
。
private Lock lock = new ReentrantLock();public void method() {lock.lock();try {// 代码} finally {lock.unlock(); // 必须手动释放}
}
- 核心区别对比
特性 | synchronized | Lock (ReentrantLock) |
---|---|---|
实现方式 | JVM内置关键字 | Java类库实现 |
锁获取/释放 | 自动 | 手动(lock()/unlock()) |
锁类型 | 非公平锁 | 可配置公平/非公平锁 |
可中断性 | 不可中断 | 支持(lockInterruptibly()) |
尝试获取锁 | 不支持 | 支持(tryLock()) |
超时机制 | 不支持 | 支持(tryLock(time, unit)) |
条件变量 | 单一条件(wait/notify) | 多条件(newCondition()) |
性能 | JDK6后优化,低竞争时性能好 | 高竞争时性能更优 |
锁粒度 | 方法或代码块级别 | 可更细粒度控制 |
- 底层原理
3.1 synchronized实现
• 锁升级机制:偏向锁→轻量级锁→重量级锁
• 对象头Mark Word存储锁状态
• Monitor机制:每个对象关联一个Monitor,包含_EntryList和_WaitSet
3.2 Lock实现
• 基于AQS(AbstractQueuedSynchronizer)框架
• 使用CLH队列管理等待线程
• 支持公平/非公平两种获取锁方式
- 高级特性
4.1 Lock特有功能
// 1. 尝试获取锁
if (lock.tryLock()) {try {// 获取锁成功} finally {lock.unlock();}
}// 2. 可中断获取锁
try {lock.lockInterruptibly();// ...
} catch (InterruptedException e) {// 处理中断
}// 3. 多条件变量
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
4.2 synchronized优化
• 锁消除:JVM检测到不可能存在共享数据竞争时消除锁
• 锁粗化:将连续的同步块合并为一个更大的同步块
• 自适应自旋:根据历史数据动态调整自旋次数
- 使用场景建议
优先使用synchronized
• 简单的同步需求
• 锁的获取和释放在同一方法内
• 不需要高级功能(如超时、中断等)
选择Lock的情况
• 需要公平锁
• 需要尝试非阻塞获取锁
• 需要多个条件变量
• 锁需要在多个方法间传递
• 高竞争环境下对性能有更高要求
- 实际案例
6.1 生产者-消费者模型(Lock实现)
class Buffer {private final Lock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();public void produce() {lock.lock();try {while (isFull()) {notFull.await();}// 生产...notEmpty.signal();} finally {lock.unlock();}}
}
6.2 单例模式(synchronized实现)
class Singleton {private static volatile Singleton instance;public static Singleton getInstance() {if (instance == null) {synchronized(Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
- 总结
synchronized
和Lock
都是Java中实现线程同步的有效机制,各有优缺点。理解它们的底层原理和适用场景,才能在实际开发中做出合理选择。对于大多数简单场景,synchronized
已经足够;当需要更灵活的锁控制时,Lock
是更好的选择。