Java 中的锁机制详解

Java 中的锁机制是实现多线程并发控制的核心手段,用于保证临界资源在多线程访问时的安全性。锁的设计与实现主要依赖 JDK 提供的 synchronizedjava.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 等)

附录:锁死与锁优化

死锁四大必要条件

  1. 互斥使用
  2. 不可抢占
  3. 请求与保持
  4. 循环等待

锁优化方向

  • 减少锁粒度
  • 减少锁持有时间
  • 使用无锁 / CAS 替代
  • 使用读写锁区分读写冲突

总结

Java 的锁机制涵盖了从语言级别到并发包的全套支持,配合 JVM 锁优化(偏向、轻量、重量级锁),可以根据业务并发需求灵活选型。

锁的选型应关注:

  • 线程竞争激烈程度
  • 可读可写并发比例
  • 是否需要中断或公平性控制
  • 对性能的敏感度