定义

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 为优化性能自动实现的,无需用户干预。