精心整理了最新的面试资料和简历模板,有需要的可以自行获取
Java 并发编程:synchronized 与 Lock 的深度对比
在 Java 多线程编程中,同步机制是保证线程安全的核心手段。synchronized
关键字和 Lock
接口是实现线程同步的两种主要方式,二者在设计理念、功能特性和使用场景上存在显著差异。本文将深入探讨它们的区别,并通过代码示例说明适用场景。
一、实现原理对比
1. synchronized
-
关键字特性
synchronized
是 Java 语言层面的原生支持,属于 隐式锁。编译器会在代码块前后自动插入加锁(monitorenter
)和解锁(monitorexit
)指令。 -
JVM 监控机制
通过对象头的 Mark Word 实现锁状态记录,支持 偏向锁、轻量级锁、重量级锁 的锁升级机制(JDK 6+优化)。
// 示例:synchronized 修饰代码块
public void syncMethod() {
synchronized (this) {
// 临界区代码
}
}
2. Lock
-
API 接口
Lock
是java.util.concurrent.locks
包中的接口(如ReentrantLock
),属于 显式锁,需要手动调用lock()
和unlock()
。 -
AQS 实现
基于 AbstractQueuedSynchronizer(AQS) 队列同步器,通过 CAS 操作和 CLH 队列管理线程竞争。
// 示例:Lock 基本用法
Lock lock = new ReentrantLock();
public void lockMethod() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
}
二、功能特性对比
1. 锁的获取方式
特性 | synchronized | Lock |
---|---|---|
阻塞机制 | 不可中断等待 | 支持 lockInterruptibly() |
超时获取 | 不支持 | 支持 tryLock(long, TimeUnit) |
公平性 | 非公平锁(默认) | 可配置公平锁(ReentrantLock(true) ) |
2. 锁的灵活性
-
synchronized
锁的释放由 JVM 自动管理,但无法跨方法释放锁。 -
Lock
提供更细粒度的控制(如条件变量Condition
),可通过newCondition()
实现多条件等待队列。
// 示例:Condition 实现精准唤醒
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void await() throws InterruptedException {
lock.lock();
try {
condition.await(); // 释放锁并等待
} finally {
lock.unlock();
}
}
public void signal() {
lock.lock();
try {
condition.signal(); // 唤醒等待线程
} finally {
lock.unlock();
}
}
三、性能差异
1. 历史背景
- JDK 1.5 之前,
synchronized
因重量级锁性能较差。 - JDK 1.6 引入 锁消除、锁粗化、适应性自旋 等优化后,性能与
Lock
接近。
2. 高并发场景
- synchronized:在低竞争场景下表现更好(JVM 优化成熟)。
- Lock:在高竞争场景下(如大量线程争抢)可通过 自旋+CAS 减少上下文切换,性能更优。
四、使用场景建议
推荐使用 synchronized
- 简单的同步需求(如单方法内的线程安全)。
- 需要 JVM 自动管理锁释放,避免人为遗漏
unlock()
。
推荐使用 Lock
- 需要 可中断锁、超时锁、公平锁 等高级特性。
- 需要 多条件变量(如生产者-消费者模型中的独立等待队列)。
- 跨方法控制锁的获取与释放。
五、总结对比表
对比维度 | synchronized | Lock(如 ReentrantLock) |
---|---|---|
实现级别 | JVM 原生支持 | Java API 实现 |
锁释放 | 自动释放 | 必须手动调用 unlock() |
功能扩展 | 有限 | 支持中断、超时、公平锁、条件变量 |
代码灵活性 | 锁粒度较粗 | 细粒度控制 |
性能 | 低竞争场景更优 | 高竞争场景更优 |
调试支持 | 难以获取锁状态 | 可通过方法检测锁状态(如 isLocked() ) |
六、最终建议
- 优先选择
synchronized
:适用于简单同步场景,避免显式锁的管理复杂性。 - 选择
Lock
:当需要高级功能或对性能有极致要求时(如分布式锁的本地实现)。
通过理解二者的核心差异,开发者可以根据实际需求选择最合适的同步工具,从而编写出高效、健壮的并发程序。
希望这篇文章能帮助您清晰理解 synchronized
和 Lock
的异同!