
锁的升级、膨胀和降级
定义
1. 锁的升级(Lock Promotion)
- 含义:特指 读写锁(ReadWriteLock) 中,一个线程在持有读锁的情况下尝试获取写锁的操作。
- 限制:这种操作是禁止的,会导致死锁。因为写锁需要等待所有读锁释放(包括自身持有的),而自身又在等待写锁获取成功后才能继续执行释放读锁的逻辑,形成循环等待。
- 示例:
ReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock(); // 获取读锁
rwLock.writeLock().lock(); // 尝试升级为写锁(会死锁)
2. 锁的膨胀(Lock Inflation)
- 含义:特指 synchronized 锁的状态升级,即从 偏向锁 → 轻量级锁 → 重量级锁 的过程。
- 允许性:这种膨胀是 JVM 自动支持的,目的是在不同竞争程度下优化锁的性能。
- 示例:
public class LockInflationExample {
private final Object lock = new Object();
public void method() {
synchronized (lock) { // 锁状态可能从偏向锁膨胀到轻量级锁或重量级锁
// 同步代码块
}
}
}
3. 锁降级
- 场景:写锁持有者完成数据修改后,可能需要读取修改后的数据并保证这段读取过程的线程安全(避免其他线程在此时修改数据)。
- 安全性:
- 写锁是独占锁,持有写锁时,其他线程无法获取读锁或写锁,因此在持有写锁时获取读锁不会有竞争。
- 降级过程(写锁 → 读锁)不会形成死锁:线程先获取读锁(此时仍持有写锁,其他线程无法干扰),再释放写锁,最终持有读锁,逻辑上无循环等待。
- 示例:
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.writeLock().lock(); // 获取写锁
try {
// 修改数据
rwLock.readLock().lock(); // 降级:先获取读锁
} finally {
rwLock.writeLock().unlock(); // 释放写锁,保留读锁
}
// 此时持有读锁,可安全读取数据
rwLock.readLock().unlock();
锁降级的核心作用是 “让写操作的结果对后续的读操作可见”。 如果写锁释放后再获取读锁,可能导致其他线程在中间修改数据,破坏一致性。而降级过程中,读锁的获取在写锁释放之前,确保了读取的是自己修改后的最新数据。
三、为什么读写锁(ReadWriteLock)支持锁降级?
锁降级 特指 读写锁(如 ReentrantReadWriteLock
) 中,一个线程在持有写锁的情况下,先获取读锁,再释放写锁的过程。这种操作是被允许的,原因如下:
四、为什么 synchronized 没有锁降级?
synchronized
是 排他锁(无论状态是偏向锁、轻量级锁还是重量级锁,本质都是独占的),不存在“读锁”“写锁”的区分,因此“锁降级”对它而言没有意义,具体原因如下:
1. synchronized 只有一种锁类型
synchronized
从设计上就是 独占锁,任何时候最多只有一个线程持有锁,不存在“读共享、写独占”的场景。 它的“锁膨胀”(偏向锁→轻量级锁→重量级锁)是 同一把锁的状态变化,而非锁类型的转换(如读锁→写锁)。状态变化的目的是优化性能,而非支持多线程的读写协作。
2. 无需降级的逻辑基础
由于 synchronized
是独占锁,线程持有锁时可以同时完成“读”和“写”操作,且其他线程无法干扰。释放锁后,其他线程获取的是同一把锁,不存在“写后读”的数据一致性问题(synchronized
本身通过 happens-before 规则 保证了锁释放与获取的可见性)。 因此,synchronized
不需要通过“降级”来维护数据一致性,自然也就没有设计锁降级的机制。
维度 | 读写锁(支持降级) | synchronized(无降级) |
---|---|---|
锁类型 | 区分读锁(共享)和写锁(独占) | 只有独占锁,无读写区分 |
降级目的 | 保证写操作后的数据可见性,避免中间被其他线程修改 | 无需降级,独占性本身保证读写操作的原子性和可见性 |
状态本质 | 不同类型锁的转换(写锁→读锁) | 同一把锁的状态优化(偏向→轻量→重量) |
简言之,锁降级是读写锁为协调“读共享、写独占”场景而设计的特性,而 synchronized
作为独占锁,不存在这种场景需求,因此没有锁降级机制。
简言之,锁降级是读写锁为协调“读共享、写独占”场景而设计的特性,而 **synchronized
作为独占锁,不存在这种场景需求,因此没有锁降级机制。
特性 | 读写锁(ReadWriteLock) | synchronized 锁 |
---|---|---|
升级/膨胀 | 不允许锁升级(会导致死锁) | 允许锁膨胀(偏向 → 轻量级 → 重量级) |
触发条件 | 读锁持有者尝试获取写锁 | 多线程竞争加剧 |
实现方式 | 需手动释放读锁,再获取写锁 | JVM 自动升级锁状态 |
目的 | 避免死锁 | 优化性能 |
- 锁不可以升级:读写锁的升级操作会导致死锁,因此被禁止。
- 锁可以膨胀:synchronized 锁的状态升级(膨胀)是 JVM 为优化性能自动实现的,无需用户干预。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 surfingYu
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果