Java中锁的分类及机制详解

2025年06月29日/ 浏览 6


一、锁的本质与分类体系

在多线程编程中,锁是协调资源访问的核心机制。Java的锁体系可分为三个维度:

  1. 按线程竞争策略:悲观锁 vs 乐观锁
  2. 按锁的公平性:公平锁 vs 非公平锁
  3. 按实现层级:JVM内置锁 vs JDK显式锁

二、悲观锁与乐观锁

1. 悲观锁(Pessimistic Locking)

认为并发冲突必然发生,典型代表是synchronized关键字:

java
public synchronized void transfer(Account target, int amount) {
this.balance -= amount;
target.balance += amount;
}

特性:
– 独占资源直至释放
– 适合写操作频繁场景
– 可能引发线程阻塞

2. 乐观锁(Optimistic Locking)

假设冲突概率低,采用版本号/CAS机制实现。如AtomicInteger

java
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // 基于CAS操作

实现要点:
– 比较并交换(Compare-And-Swap)
– 适合读多写少场景
– 需处理失败重试

三、公平锁与非公平锁

1. 公平锁(Fair Lock)

按照线程申请顺序分配资源,如:

java
ReentrantLock fairLock = new ReentrantLock(true);

特点:
– 避免线程饥饿
– 上下文切换开销较大

2. 非公平锁(Nonfair Lock)

允许插队抢占资源,默认实现:

java
ReentrantLock nonFairLock = new ReentrantLock();

优势:
– 吞吐量更高
– 可能出现长时等待

四、重量级锁与轻量级锁

1. 重量级锁

传统synchronized在竞争激烈时会升级为重量级锁,涉及操作系统互斥量。

2. 轻量级锁

通过CAS操作尝试获取锁,失败才升级为重量级锁。JVM的锁优化包括:
– 偏向锁
– 自旋锁
– 锁消除

五、可重入锁(ReentrantLock)

允许同一线程多次获取同一把锁:

“`java
ReentrantLock lock = new ReentrantLock();

void recursiveMethod(int n) {
lock.lock();
try {
if(n > 0) {
recursiveMethod(n-1);
}
} finally {
lock.unlock();
}
}
“`

优势:
– 避免自我死锁
– 支持条件变量(Condition)

六、死锁产生与预防

典型死锁场景:
“`java
// 线程1
synchronized(resourceA) {
synchronized(resourceB) {…}
}

// 线程2
synchronized(resourceB) {
synchronized(resourceA) {…}
}
“`

预防策略:
1. 按固定顺序获取资源
2. 设置超时时间(tryLock)
3. 使用死锁检测工具

七、锁的性能优化建议

  1. 缩小同步代码块范围
  2. 读写分离时采用ReadWriteLock
  3. 考虑无锁数据结构(如ConcurrentHashMap)
  4. 监控锁竞争情况(JVisualVM)

通过合理选择锁机制,开发者可以在线程安全与系统性能之间取得平衡。理解不同锁的特性及适用场景,是构建高并发系统的关键基础。
“`

picture loss