Java读写锁降级

锁降级并不是读锁 / 写锁有 "等级数值",而是指锁的 "独占 / 共享" 状态的转换,且只能从 "更严格的独占状态" 降到 "宽松的共享状态"

一、先搞懂:为什么会有 "锁降级" 这个说法?

读写锁里的 "等级",本质是锁的 "排他性强度"

  • 写锁(排他锁):强度最高 → 独占资源,不允许任何线程(读 / 写)同时访问。
  • 读锁(共享锁):强度更低 → 允许其他读线程共享资源,只排斥写线程。

"锁降级" 就是:持有写锁的线程,在不释放写锁的前提下先获取读锁,再释放写锁,最终只持有读锁。这个过程是 "从高强度的独占锁,降到低强度的共享锁",所以叫 "降级"。

反过来,"锁升级"(读锁→写锁)是不被允许的 ------ 如果一个线程先拿了读锁,再尝试拿写锁,会直接导致死锁(自己等自己释放读锁,其他读线程也在占用,永远等不到)。

二、锁降级的核心目的:保证数据一致性

锁降级不是 "炫技",而是为了在写操作完成后,安全地读取自己刚写入的数据,且期间不让其他写线程插队修改数据。

举个生活例子:

你是仓库管理员(线程),拿着 "仓库钥匙(写锁)" 进去修改库存(写操作)。改完后,你想确认一下改得对不对(读操作),这时候:

  • 如果你先把钥匙还了(释放写锁),再去拿 "查看权限(读锁)",中间可能有其他管理员(其他线程)插队拿钥匙改库存,你看到的就不是自己刚改的数了。
  • 如果你先拿 "查看权限(读锁)",再还钥匙(释放写锁),中间没有空窗期,能确保你看的是自己刚改的数,之后也能和其他员工(读线程)一起查看。
java 复制代码
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockDowngradeDemo {
    private final Map<String, String> cache = new HashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();

    // 锁降级的核心方法
    public String updateAndRead(String key, String value) {
        // 1. 先获取写锁(高强度独占锁),执行写操作
        writeLock.lock();
        String result = null;
        try {
            System.out.println(Thread.currentThread().getName() + " 持有写锁,执行写操作");
            cache.put(key, value); // 写入数据

            // 2. 关键:在释放写锁前,先获取读锁(降级的核心步骤)
            // 这一步不会阻塞,因为当前线程已经持有写锁,读写锁允许写线程获取读锁
            readLock.lock();
            System.out.println(Thread.currentThread().getName() + " 成功获取读锁,准备降级");
        } finally {
            // 3. 释放写锁,此时线程只持有读锁(完成降级)
            writeLock.unlock();
            System.out.println(Thread.currentThread().getName() + " 释放写锁,完成锁降级");
        }

        // 4. 持有读锁读取数据,此时其他写线程无法修改,读线程可以共享
        try {
            System.out.println(Thread.currentThread().getName() + " 持有读锁,读取数据:" + cache.get(key));
            result = cache.get(key);
        } finally {
            // 5. 最后释放读锁
            readLock.unlock();
            System.out.println(Thread.currentThread().getName() + " 释放读锁");
        }
        return result;
    }

    public static void main(String[] args) {
        LockDowngradeDemo demo = new LockDowngradeDemo();
        // 单线程执行锁降级
        new Thread(() -> demo.updateAndRead("user", "张三"), "线程A").start();

        // 多线程验证:线程A降级后,线程B可以获取读锁,但线程C的写锁会被阻塞
        new Thread(() -> {
            demo.readLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 拿到读锁,读取user:" + demo.cache.get("user"));
            } finally {
                demo.readLock.unlock();
            }
        }, "线程B(读)").start();

        new Thread(() -> {
            demo.writeLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 拿到写锁,修改user为李四");
                demo.cache.put("user", "李四");
            } finally {
                demo.writeLock.unlock();
            }
        }, "线程C(写)").start();
    }
}

线程A 持有写锁,执行写操作

线程A 成功获取读锁,准备降级

线程A 释放写锁,完成锁降级

线程A 持有读锁,读取数据:张三

线程B(读) 拿到读锁,读取user:张三 // 线程B和A共享读锁,并行执行

线程A 释放读锁

线程C(写) 拿到写锁,修改user为李四 // 只有读锁都释放后,写锁才会执行


text 复制代码
线程操作流程:
1. 拿写锁 → 独占资源,执行写操作(此时所有读/写线程阻塞)
2. 拿读锁 → 因为当前线程持有写锁,这一步不会阻塞(读写锁的可重入特性)
3. 释放写锁 → 此时线程只持有读锁(完成降级),其他读线程可以加读锁,但写线程仍阻塞
4. 执行读操作 → 安全读取自己刚写的数据
5. 释放读锁 → 所有线程可正常竞争锁
相关推荐
2601_962299242 小时前
Azure python操作系统列表
python·操作系统·azure·虚拟机·存储配置文件
2601_962071572 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
zww89491112 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·eclipse
学术 学术 Fun3 小时前
如何用 API 与 Webhook 批量把图表图片转换成 VSDX
python·自动化·api·visio
淡海水3 小时前
07-04-并发-ConcurrentBag-T-工作窃取WorkStealing算法
开发语言·算法·c#·bag·concurrent·workstealing
2601_962100543 小时前
python包和模块的内容整理
python·模块·导入·虚拟环境·
CS_Zero4 小时前
C语言sizeof是函数吗?
c语言·开发语言
二进制漫游记4 小时前
FastAPI项目集成 Qdrant向量数据库+阿里云Embedding完整实战(工具封装+业务调用)
数据库·python·阿里云·embedding
-今昭-4 小时前
《V2V 迁移实战:将 VMware 虚拟机转为 OpenStack 可用 Glance qcow2 镜像》
开发语言·python
2601_962381585 小时前
【转】Python渗透测试工具:sqlmap
python·渗透测试·sql注入·sqlmap·数据库安全