Java 中的锁机制是实现多线程并发控制的核心手段,用于保证临界资源在多线程访问时的安全性。锁的设计与实现主要依赖 JDK 提供的 synchronized
和 java.util.concurrent.locks
包。
一、锁的分类总览
分类维度 | 锁类型 |
---|---|
实现层面 | Java 内置锁(synchronized) JUC 显式锁(ReentrantLock 等) |
可重入性 | 可重入锁 / 非可重入锁 |
公平性 | 公平锁 / 非公平锁 |
读写粒度 | 独占锁 / 共享锁(如 ReadWriteLock) |
乐观与悲观 | 乐观锁(CAS) / 悲观锁 |
锁粒度与升级 | 偏向锁 → 轻量级锁 → 重量级锁 |
其他特性 | 自旋锁、可中断锁、可定时锁 |
二、Java 常见锁类型详解
1. synchronized(内置锁)
特点:
- 自动获取和释放锁
- 支持可重入 、阻塞式 、重量级
- 编译器层面支持,底层使用 monitor(对象监视器)
使用方式:
java
synchronized(obj) {
// 临界区
}
或用于方法:
java
public synchronized void doSomething() {}
适用场景:
- 代码简单的同步场景
- 不需要手动加解锁的逻辑
- 并发竞争不激烈的情况下性能较好(配合锁优化)
2. ReentrantLock(显示锁)
特点:
- 可重入
- 支持中断锁 、定时锁 、公平锁 、条件变量
- 手动加锁与释放(需
finally
中 unlock)
使用方式:
java
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
// 临界区
} finally {
lock.unlock();
}
适用场景:
- 需要更高级控制功能(如公平性、可中断、条件变量)
- 更灵活地配合条件对象实现等待/通知机制
3. ReadWriteLock(读写锁)
特点:
- 提供读锁(共享)和写锁(独占)
- 支持多个线程并发读,写操作需互斥
使用方式:
java
ReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();
适用场景:
- 读多写少的缓存类、配置类
- 提高读并发性能
4. StampedLock(JDK 8 新增)
特点:
- 不可重入
- 三种模式:写锁、悲观读锁、乐观读锁
- 适用于对性能要求极高的读写场景
示例:
java
long stamp = stampedLock.tryOptimisticRead();
try {
// 读操作
if (!stampedLock.validate(stamp)) {
// fallback to pessimistic
}
} finally {
stampedLock.unlock(stamp);
}
适用场景:
- 高并发读访问
- 优化 CPU 缓存一致性开销(如 LRU 缓存)
5. 乐观锁(CAS)
特点:
- 不阻塞,基于版本号或原子变量进行更新
- 实现机制依赖
Unsafe.compareAndSwapXxx
使用场景:
- 原子类:
AtomicInteger
,AtomicLong
等 - 非常适合频繁读、偶尔写的场景,如计数器、非阻塞队列
6. 自旋锁
特点:
- 在获取不到锁时,不立即挂起线程,而是循环尝试
- 减少线程上下文切换,但可能造成 CPU 空转
应用场景:
- 锁等待时间非常短的场景,如 CPU 计算密集型任务
三、锁升级过程(JVM 优化)
JVM 会根据竞争情况自动将锁从低成本升级为高成本锁:
text
偏向锁 → 轻量级锁 → 重量级锁
锁类型 | 描述 |
---|---|
偏向锁 | 只有一个线程竞争,自动偏向该线程 |
轻量级锁 | 多线程竞争但没有阻塞 |
重量级锁 | 多线程激烈竞争,发生阻塞 |
四、常见锁的比较表
锁类型 | 可重入 | 阻塞 | 公平可选 | 中断响应 | 性能 |
---|---|---|---|---|---|
synchronized | ✅ | ✅ | ❌ | ❌ | 中 |
ReentrantLock | ✅ | ✅ | ✅ | ✅ | 高 |
ReadWriteLock | ✅ | ✅ | ✅ | ✅ | 高(读多) |
StampedLock | ❌ | ✅ | ❌ | ❌ | 极高 |
乐观锁(CAS) | ❌ | ❌ | ❌ | ❌ | 极高 |
五、典型应用场景总结
场景类型 | 推荐锁方案 |
---|---|
简单线程同步 | synchronized |
复杂并发控制 | ReentrantLock |
读多写少 | ReadWriteLock / StampedLock |
频繁原子操作 | 原子类(CAS) |
高性能读缓存 | StampedLock 乐观读 |
线程间通知机制 | Lock + Condition |
秒杀、抢单、库存 | 分布式锁(Redisson 等) |
附录:锁死与锁优化
死锁四大必要条件
- 互斥使用
- 不可抢占
- 请求与保持
- 循环等待
锁优化方向
- 减少锁粒度
- 减少锁持有时间
- 使用无锁 / CAS 替代
- 使用读写锁区分读写冲突
总结
Java 的锁机制涵盖了从语言级别到并发包的全套支持,配合 JVM 锁优化(偏向、轻量、重量级锁),可以根据业务并发需求灵活选型。
锁的选型应关注:
- 线程竞争激烈程度
- 可读可写并发比例
- 是否需要中断或公平性控制
- 对性能的敏感度