读写锁简介

详解读写锁 读写锁(Readers-Writer Lock)是一种用于多线程编程中的同步机制,主要用于控制对共享资源的访问。它特别适用于读取操作远多于写入操作的场景,通过允许多个线程同时读取共享资源,而只允许一个线程写入共享资源,从而提高并发性能和吞吐量。读写锁的基本概念是将锁分为两部分:读锁和写锁。读锁允许多个线程同时获得,因为读操作本身是线程安全的;而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。 阅读详情

ReentrantReadWriteLock

使用场景

当读操作远远高于写操作时,这时候使用 结果 3 3 t0 读写锁 让 读-读 可以并发,提高性能。 类似于数据库中的 from ... lock in share mode

特点

读读可以并发,读写和写写互斥

读锁不支持条件变量

重入时升级不支持:即持有读锁的情况下去获取写锁,会导致获取写锁永久等待

重入时降级支持:即持有写锁的情况下去获取读锁

应用

缓存,保证缓存的读取和数据库保持一致。一般情况下,先更新数据库,再清理缓存;

样例代码

package concurrent;

import java.util.concurrent.locks.ReentrantReadWriteLock;

class CachedData {
    Object data;
    // 是否有效,如果失效,需要重新计算 data
    volatile boolean cacheValid;
    final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    void processCachedData() {
        rwl.readLock().lock();
        if (!cacheValid) {
            // 获取写锁前必须释放读锁
            rwl.readLock().unlock();
            rwl.writeLock().lock();
            try {
                // 判断是否有其它线程已经获取了写锁、更新了缓存, 避免重复更新
                if (!cacheValid) {
                    data = ...
                    cacheValid = true;
                }
                // 降级为读锁, 释放写锁, 这样能够让其它线程读取缓存
                rwl.readLock().lock();
            } finally {
                rwl.writeLock().unlock();
            }
        }
        // 自己用完数据, 释放读锁
        try {
            use(data);
        } finally {
            rwl.readLock().unlock();
        }
    }
}

 备注: 

释放读锁和获取写锁之间,怎么能确保没有别的线程获取了写锁?参照这个代码样例。 一般是获取,获取完了之后,再做双重非空判断。非空判断 ---》加锁 ---》非空判断,类似单例模式之中的双重锁写法。

这里的非空判断,可以替换为对voliate修饰的变量的判断,类似于上面代码中的写法

StampedLock

特点

在使用读锁、写锁时都必须配合【戳】使用;先乐观读,如果【戳】变化,代表已经被其他线程更改过了,升级锁。

乐观读,StampedLock 支持 tryOptimisticRead() 方法(乐观读),读取完毕后需要做一次 戳校验 如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全。

和ReentrantReadWriteLock对比

StampedLock 不支持条件变量

StampedLock 不支持可重入

样例代码

package concurrent;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.StampedLock;

import static util.Sleeper.sleep;

@Slf4j(topic = "c.TestStampedLock")
public class TestStampedLock {
    public static void main(String[] args) {
        DataContainerStamped dataContainer = new DataContainerStamped(1);
        new Thread(() -> {
            dataContainer.read(1);
        }, "t1").start();
        sleep(0.5);
        new Thread(() -> {
//            dataContainer.read(0);
            dataContainer.write(0);
        }, "t2").start();
    }
}

@Slf4j(topic = "c.DataContainerStamped")
class DataContainerStamped {
    private int data;
    private final StampedLock lock = new StampedLock();

    public DataContainerStamped(int data) {
        this.data = data;
    }

    public int read(int readTime) {
        long stamp = lock.tryOptimisticRead();
        log.debug("optimistic read locking...{}", stamp);
        sleep(readTime);
        if (lock.validate(stamp)) {
            log.debug("read finish...{}, data:{}", stamp, data);
            return data;
        }
        // 锁升级 - 读锁
        log.debug("updating to read lock... {}", stamp);
        try {
            stamp = lock.readLock();
            log.debug("read lock {}", stamp);
            sleep(readTime);
            log.debug("read finish...{}, data:{}", stamp, data);
            return data;
        } finally {
            log.debug("read unlock {}", stamp);
            lock.unlockRead(stamp);
        }
    }

    public void write(int newData) {
        long stamp = lock.writeLock();
        log.debug("write lock {}", stamp);
        try {
            sleep(2);
            this.data = newData;
        } finally {
            log.debug("write unlock {}", stamp);
            lock.unlockWrite(stamp);
        }
    }
}

读写锁ReentrantReadWriteLock详解 读写锁、ReentrantReadWriteLock 阅读详情

相关推荐

Pthread实现读写锁

Pthread实现读写锁 1. 博客内容: 编写Pthread程序,使用两个条件变量和一个互斥量来实现一个读写锁。比较当读优先级更高时和写优先级更高时程序的性能。并进行归纳总结。 2. 实现思路: 2.1 读写锁: 读写锁是一种特殊的锁,它把对资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。 一次只有一个线程可以占有写模式...

zhangjt33的博客 1353

读写锁 (ReadWriteLock)

Java读写锁(ReadWriteLock)是一种高效并发控制机制,它允许多个线程同时读取共享数据,但写入时保证独占访问。核心特点是"读读共享、读写互斥、写写互斥",特别适合读多写少的场景(如缓存、配置管理)。Java通过ReentrantReadWriteLock实现该功能,支持锁降级(写锁降为读锁)和公平性选择。使用时需注意避免写锁饥饿问题,确保在finally块中释放锁。相比synchronized,读写锁在读取频繁的场景下能显著提升性能,但写操作频繁时反而不适用。典型应用包括图书

2301_80096362的博客 517

【新华三】通过路由复制实现Public与VRF路由互通

如上图所示,S6900设备里有两张表,一张是public路由表,默认所有的路由都存放在public路由表里;除此之外还创建了VRF test,因此此设备还有VRF test路由表。通过路由复制实现Public路由和VRF路由互通,默认情况下VRF里的路由单独一张路由表,默认情况下与public路由表相互隔离,两张表之间不可互访。此时的public路由表里面并没有test的路由表。public路由表与VRF路由表之间相互隔离。此时VRF test里的路由也没有其他VRF或Public里的路由,相互隔离。

五大连池的镜子 5279

读写锁

ReadWriteLock也是一个接口,提供了readLock和writeLock两种锁的操作机制,一个资源可以被多个线程同时读,或者被一个线程写,但是不能同时存在读和写线程。    基本规则:  读读不互斥 读写互斥 写写互斥      问题: 既然读读不互斥,为何还要加读锁    答:  如果只是读,是不需要加锁的,加锁本身就有性能上的损耗             如果读可以不是最新...

weixin_40839342的博客 4264

Dify+firecrawl:一个超好用的网页转Markdown API,打造你的第一个能检索爬虫RAG知识库的聊天机器人

Firecrawl是一个超简单的API服务——你扔给它一个URL,它就能把整个网站(包括子页面!)的内容自动抓下来,并且转换成干净、易读的Markdown格式。不用配置网站的站点地图,不用写爬虫规则,API调一下,数据直接到手。接下来我们一起本地部署吧!

2501_91673550的博客 2991

GoldenDB 兼容模式冲突场景解析:MySQL 连接模式 vs Oracle 语法兼容

GoldenDB 兼容模式冲突场景解析:MySQL 连接模式 vs Oracle 语法兼容

weixin_45207751的博客 2250

ReadWriteLock读写锁简介、使用场景分析以及锁降级

what 像ReentrantLock,Synchronized关键字,Mutex都是排它锁,这些锁在同一时刻只允许一个线程访问,而读写锁在同一时刻可以允许多个读线程访问,但是写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性能相对于一般的排它锁有了很大提升。 除了保证写操作对读操作的可见性以及并发性的提升之外,读写锁能够简化读写交互场景的编程方式。假设在程序中定义一个共享的用作缓存的数据结构。它大部分时间都是提供读服务,例如查询和搜索,而

d303577562的博客 1556

机器学习——笔记整理(原理、python代码)——反反复复,出精活!

回顾知识,检查自我,开拓新域。 机器学习1.监督学习 机器学习简介: 机器学习是实现人工智能的手段,其主要研究内容是如何利用数据或经验进行学习,改善具体算法的性能。 多领域交叉,涉及概率论、统计学,算法复杂度理论等多门学科 广泛应用于网络搜索、垃圾邮件过滤、推荐系统、广告投放、信用评价、欺诈检测、股票交易和医疗诊断等应用。 机器学习分类: 机器学习一般分为下面几种类别 监督学习 ( Supervised Learning) 无监督学习 ( Unsupervised Learning) 强化学习(

weixin_45666566的博客 6487

158-166、缓存-分布式锁-分布式锁原理与使用、Redisson简介&整合、锁测试、看门狗原理-redisson如何解决死锁、读写锁测试、读写锁补充、闭锁测试、信号量测试、缓存一致性解决

158、缓存-分布式锁-分布式锁原理与使用 159、缓存-分布式锁-Redisson简介&整合 160、缓存-分布式锁-Redisson-lock锁测试 161、缓存-分布式锁-Redisson-lock看门狗原理-redisson如何解决死锁 162、缓存-分布式锁-Redisson-读写锁测试 163、缓存-分布式锁-Redisson-读写锁补充 164、缓存-分布式锁-Redisson-闭锁测试 165、缓存-分布式锁-Redisson-信号量测试 166、缓存-分布式锁-缓存一致性解决 .

zouxuhang的博客 305

Visual Studio调试时遇到ntdll.dll的PDB文件缺失?别慌,这3个方法帮你搞定(附详细步骤)

本文详细解析了Visual Studio调试时ntdll.dll的PDB文件缺失问题,提供了3种实用解决方案:调整调试设置、配置符号服务器与缓存目录、手动下载管理符号文件。通过分步指导和高级技巧,帮助开发者快速恢复完整的调试功能,特别适用于Windows平台下的C++项目开发。

weixin_42537919的博客 513

Python之ae-toolbox包语法、参数和实际应用案例

ae-toolbox(全称 after-effects-toolbox)是 Python 生态中专门用于 Adobe After Effects(AE)自动化操作 的工具包,基于 AE 的 ExtendScript(JSX)桥接技术,实现 Python 与 AE 的跨语言通信。

王国平的博客 1174

Java多线程之ReadWriteLock读写锁简介与使用教程

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6558073.html 普通的锁在对某一内容加锁后,其他线程是不能访问的。但是我们要考虑这种情况:如果当前加锁的内容中,有些操作是可以并发执行的,有些是不可以并发,两种操作之间又存在互斥,怎么才能最优化地加锁呢?我们引入了ReadWriteLock,人为地将这两种操作划分为 读、写 操作...

a631278993的博客 203

手把手教您解决 AdGuard Home DNS重写功能失效的问题

AdGuard Home 设置了 DNS 重写,规则明明没问题,客户端却死活解析不到内网 IP?🤯 别急着重装!🚫 本文手把手教你如何解决软路由 DNS 解析“玄学”故障!🛠️🚀

XiaoqiangClub的博客 919

【JUC】12.读写锁与StampedLock[完结]

读写锁是指ReentrantReadWriteLock类该类能被多个读线程访问或者一个写线程访问,但是不能同时存在读写线程其特点主要是:一体两面、读写互斥、读读共享有线程在写的时候,其他线程不能读;有线程在读的时候,其他线程不能写StampedLock优化的主要是ReentrantReadWriteLock出现的锁饥饿问题stamp代表的是锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值回顾锁饥饿问题。

沉迷写代码的程序猿的博客 506

【AI Agent 记忆共享实战】【下篇】多 Agent 会话 Session 统一共享实战:全链路工程落地、采集归一、MCP 服务、私有化部署、源码级实战

中篇我们已经锁定最终最优架构方案: 非侵入式、外部旁路采集、只读归一、中心化存储、MCP 按需检索注入。摒弃「改 Agent 源码」「软链接互通」「原生 Session 互导」等不现实方案。本篇直接落地可上线、可简历复用、可个人私有化部署多 Agent 异构 Session专属采集器(Claude/CODex/DSH/OpenCode/Kimi/WorkBuddy/ 豆包)统一消息归一化解析层(解决所有 Schema 异构)增量同步、去重、时间戳对齐核心逻辑。

十年老程序猿,AI 疯狂研究专家,前沿硬核知识分享 482

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

读写锁以及其简易实现(Reader-Writer Lock)

读写锁:多读少写场景的高效同步原语 读写锁(Reader-Writer Lock)是一种优化多线程读写的同步机制,允许多线程并发读但独占写。C++17引入的std::shared_mutex通过共享锁(读)和排他锁(写)实现:读锁不互斥,写锁阻塞所有操作。其优势在于读多写少场景(如缓存、配置管理),但需注意写者饥饿(持续读阻塞写)和写竞争性能下降问题。解决方案包括写者优先策略或无锁结构。 实现原理:基于互斥锁和条件变量,核心状态包括读者数、写者活动标志和等待写者数。伪代码展示了通过条件变量协调读写线程的流程

qq_36240047的博客 749

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C++读写锁以及实现方式

适用场景:需要理解底层原理,或在不支持C++20的环境中模拟读写锁。POSIX读写锁:适用于UNIX系统的高性能场景,但需手动管理锁生命周期。C++20共享互斥锁:跨平台、安全、简洁,推荐现代C++项目使用。自定义实现:帮助理解底层原理,但需谨慎处理线程安全和性能问题。合理使用读写锁能显著优化读多写少场景的并发性,但需注意避免死锁和饥饿问题,结合具体业务场景选择最优方案。参考资料。

w148_1748的博客 2038

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++读写锁介绍

一点睛 先看看互斥锁,它只有两个状态,要么是加锁状态,要么是不加锁状态。假如现在一个线程a只是想读一个共享变量 i,因为不确定是否会有线程去写它,所以我们还是要对它进行加锁。但是这时又有一个线程b试图去读共享变量 i,发现被锁定了,那么b不得不等到a释放了锁后才能获得锁并读取 i 的值,但是两个读取操作即使是同时发生的,也并不会像写操作那样造成竞争,因为它们不修改变量的值。所以我们期望在多个线...

实践求真知 1万+

Redisson读写锁

读写锁 一次只有一个线程可以占有写模式的读写锁, 但是可以有多个线程同时占有读模式的读写锁. 正是因为这个特性, 当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞. 当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行加锁, 它必须直到所有的线程释放锁. 通常, 当读写锁处于读模式锁住状态时, 如果有另外线程试图以写模式加锁, 读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式

qq_43750656的博客 7022

Linux读写锁详解

多线程程序中,如果仅有少数线程会对共享数据进行修改,多数线程只是读取共享数据的值,就适合用读写锁解决“线程间抢夺资源”的问题。当有多个线程发出读请求时,这些线程可以同时执行,也就是说,共享数据的值可以同时被多个发出读请求的线程获取;当有多个线程发出写请求时,这些线程只能一个一个地执行(同步执行)。此外,当发出读请求的线程正在执行时,发出写请求的线程必须等待前者执行完后才能开始执行;当发出写请求的线程正在执行时,发出读请求的线程也必须等待前者执行完后才能开始执行。

m0_74282605的博客 1173

linux读写锁

3) 读写不能同时进行,写的优先级高:例如,线程A加读锁成功,又来了B线程加写锁阻塞,又来了C线程加读锁阻塞。4)线程 A 加读锁成功,然后线程 B 请求写锁,然后线程 C 请求读锁 :B 写阻塞,C 读阻塞;5)线程 A 加读写成功,然后线程 B 请求读锁,然后线程 C 请求写锁 :B 读阻塞,C 写阻塞;2)写独占-串行处理:例如,线程 A 加写锁成功,有来个 3 个线程,作读操作,3 个线程阻塞。1)读共享-并行处理:例如,线程 A 加读锁成功,有来个 3 个线程,作读操作,也可加锁成功。

m0_57678852的博客 2584

读写锁及死锁

一、读写锁有些公共数据修改的机会很少,但其读的机会很多。并且在读的过程中会伴随着查找,给这种代码加锁会降低我们的程序效率。读写锁可以解决这个问题。读写锁本质上是一种自旋锁读者——写者:同步与互斥写者——写者:互斥读者——读者:共享、没关系面试题:为什么消费者与消费者之间是互斥而读者与读者之间是没关系?因为消费者会将数据拿走,而读者只访问不会将数据拿走注意:写独占,读共享,写锁优先级高       ...

zhuboke3344的博客 4519
上一篇: ConcurrentHashMap
下一篇: ThreadLocal
Learning_foolish
博客等级 码龄9年 14粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值