并发编程13:邮戳锁StampedLock

news2024/10/6 14:33:49

文章目录

  • 13.1 关于锁的面试题
  • 13.2 简单聊聊ReentrantReadWriteLock
    • 13.2.1 是什么?
    • 13.2.2 特点
  • 13.3 面试题:有没有比读写锁更快的锁?
  • 13.4 邮戳锁StampedLock
    • 13.4.1 是什么?
    • 13.4.2 它是由饥饿问题引出
    • 13.4.3 StampedLock的特点
    • 13.4.5 乐观读模式Code演示
    • 13.4.6 StampedLock的缺点

13.1 关于锁的面试题

  • 你知道Java里面有那些锁
  • 你说说你用过的锁,锁饥饿问题是什么?
  • 有没有比读写锁更快的锁
  • StampedLock知道吗?(邮戳锁/票据锁)
  • ReentrantReadWriteLock有锁降级机制,你知道吗?

13.2 简单聊聊ReentrantReadWriteLock

13.2.1 是什么?

  • 读写锁说明

    • 一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程
  • 再说说演变

    • 无锁无序->加锁->读写锁->邮戳锁
  • 读写锁意义和特点

    • 它只允许读读共存,而读写和写写依然是互斥的,大多实际场景是”读/读线程间不存在互斥关系,只有”读/写“线程或者”写/写“线程间的操作是需要互斥的,因此引入了 ReentrantReadWriteLock
    • 一个ReentrantReadWriteLock同时只能存在一个写锁但是可以存在多个读锁,但是不能同时存在写锁和读锁,也即资源可以被多个读操作访问,或一个写操作访问,但两者不能同时进行。
    • 只有在读多写少情景之下,读写锁才具有较高的性能体现。

13.2.2 特点

  • 可重入

  • 读写兼顾

  • 结论:一体两面,读写互斥,读读共享,读没有完成的时候其他线程写锁无法获得

  • 锁降级

    • 将写锁降级为读锁------>遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级为读锁
    • 如果一个线程持有了写锁,在没有释放写锁的情况下,它还可以继续获得读锁。这就是写锁的降级,降级成为了读锁。
    • 如果释放了写锁,那么就完全转换为读锁
    • 如果有线程在读,那么写线程是无法获取写锁的,是悲观锁的策略img

13.3 面试题:有没有比读写锁更快的锁?

13.4 邮戳锁StampedLock

13.4.1 是什么?

StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWriteLock的优化

stamp 代表了锁的状态。当stamp返回零时,表示线程获取锁失败,并且当释放锁或者转换锁的时候,都要传入最初获取的stamp值。

13.4.2 它是由饥饿问题引出

  • 锁饥饿问题:

    • ReentrantReadWriteLock实现了读写分离,但是一旦读操作比较多的时候,想要获取写锁就变得比较困难了,因此当前有可能会一直存在读锁,而无法获得写锁
  • 如何解决锁饥饿问题:

    • 使用”公平“策略可以一定程度上缓解这个问题
    • 使用”公平“策略是以牺牲系统吞吐量为代价的
    • StampedLock类的乐观读锁方式—>采取乐观获取锁,其他线程尝试获取写锁时不会被阻塞,在获取乐观读锁后,还需要对结果进行校验

13.4.3 StampedLock的特点

  • 所有获取锁的方法,都返回一个邮戳,stamp为零表示失败,其余都表示成功

  • 所有释放锁的方法,都需要一个邮戳,这个stamp必须是和成功获取锁时得到的stamp一致

  • StampedLock是不可重入的,危险(如果一个线程已经持有了写锁,在去获取写锁的话会造成死锁)

  • StampedLock有三种访问模式:

    • Reading(读模式悲观):功能和ReentrantReadWriteLock的读锁类似
    • Writing(写模式):功能和ReentrantReadWriteLock的写锁类似
    • Optimistic reading(乐观读模式):无锁机制,类似与数据库中的乐观锁,支持读写并发,很乐观认为读时没人修改,假如被修改在实现升级为悲观读模式
  • 一句话:读的过程中也允许写锁介入

13.4.5 乐观读模式Code演示

  • 传统的读写锁模式----读的时候写锁不能获取
public class StampedLockDemo {
    static int number = 37;
    static StampedLock stampedLock = new StampedLock();

    public void write() {
        long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程准备修改");
        try {
            number = number + 13;
        } finally {
            stampedLock.unlockWrite(stamp);
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程结束修改");
    }

    public void read() {
        long stamp = stampedLock.readLock();
        System.out.println(Thread.currentThread().getName() + "\t" + " come in readLock codeBlock");
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + " 正在读取中");
        }
        try {
            int result = number;
            System.out.println(Thread.currentThread().getName() + "\t" + "获得成员变量值result: " + result);
            System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统的读写互斥");
        } finally {
            stampedLock.unlockRead(stamp);
        }

    }

    public static void main(String[] args) {
        StampedLockDemo resource = new StampedLockDemo();
        new Thread(() -> {
            resource.read();
        }, "readThread").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t"+" come in");
            resource.write();
        }, "writeThread").start();
    }
}
/**
 * readThread	 come in readLock codeBlock
 * readThread	 正在读取中
 * writeThread	 come in
 * readThread	 正在读取中
 * readThread	 正在读取中
 * readThread	 正在读取中
 * readThread	获得成员变量值result: 37
 * 写线程没有修改成功,读锁时候写锁无法介入,传统的读写互斥
 * writeThread	写线程准备修改
 * writeThread	写线程结束修改
 */
  • 乐观读模式----读的过程中也允许写锁介入
public class StampedLockDemo {
    static int number = 37;
    static StampedLock stampedLock = new StampedLock();

    public void write() {
        long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程准备修改");
        try {
            number = number + 13;
        } finally {
            stampedLock.unlockWrite(stamp);
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程结束修改");
    }

    public void read() {
        long stamp = stampedLock.tryOptimisticRead();

        int result = number;

        System.out.println("4秒前 stampedLock.validate方法值(true 无修改 false有修改)" + "\t" + stampedLock.validate(stamp));
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + " 正在读取...." + i + "秒后" + "stampedLock.validate方法值(true 无修改 false有修改)" + "\t" + stampedLock.validate(stamp));
        }
        if (!stampedLock.validate(stamp)) {
            System.out.println("有人修改----------有写操作");
            stamp = stampedLock.readLock();
            try {
                System.out.println("从乐观读升级为悲观读");
                result = number;
                System.out.println("重新悲观读后result:" + result);
            } finally {
                stampedLock.unlockRead(stamp);
            }
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "finally value: " + result);

    }


    public static void main(String[] args) {
        StampedLockDemo resource = new StampedLockDemo();
        new Thread(() -> {
            resource.read();
        }, "readThread").start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + " come in");
            resource.write();
        }, "writeThread").start();
    }
}
/**
 * 4秒前 stampedLock.validate方法值(true 无修改 false有修改)	true
 * readThread	 正在读取....0秒后stampedLock.validate方法值(true 无修改 false有修改)	true
 * readThread	 正在读取....1秒后stampedLock.validate方法值(true 无修改 false有修改)	true
 * writeThread	 come in
 * writeThread	写线程准备修改
 * writeThread	写线程结束修改
 * readThread	 正在读取....2秒后stampedLock.validate方法值(true 无修改 false有修改)	false
 * readThread	 正在读取....3秒后stampedLock.validate方法值(true 无修改 false有修改)	false
 * 有人修改----------有写操作
 * 从乐观读升级为悲观读
 * 重新悲观读后result:50
 * readThread	finally value: 50
 */

13.4.6 StampedLock的缺点

  • StampedLock不支持重入,没有Re开头
  • StampedLock的悲观读锁和写锁都不支持条件变量,这个也需要主要
  • 使用StampedLock一定不要调用中断操作,即不要调用interrupt()方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】IO多路转接-select

文章目录 多路转接IO模型I/O多路转接-selectselect初识select函数select的核心功能fd_set的执行流程select就绪条件基于select的服务器Sock.hppSelect_server.cpp存在的问题 select的优点select的缺点select的适用场景 多路转接IO模型 Linux下多路转接的方案常见的有三种&…

人群归因分数(Population Attributable Fraction, PAF):概念、简单计算案例

专注系列化、高质量的R语言教程 推文索引 | 联系小编 | 付费合集 本篇目录如下&#xff1a; 1 人群归因分数 1.1 相对风险度1.2 人群归因分数2 案例 2.1 示例数据2.2 计算案例12.3 计算案例22.4 计算案例33 总结 1 人群归因分数 人群归因分数&#xff08;Population Attributab…

100G CFP光模块类型应用场景详解

目前&#xff0c;全球电信行业平稳发展&#xff0c;宽带用户稳定增长&#xff0c;随着大数据市场的迅猛发展&#xff0c;骨干网、接入网和数据中心建设均需采购大量的光通信产品&#xff0c;从而给光模块行业带来了全新的市场机遇。如今&#xff0c;100G光模块已成为市场发展的…

最新DNDC模型在土地利用变化、未来气候变化下的建模方法及温室气体时空动态模拟

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。国家领导人在多次重要会议上讲到&#xff0c;要把“双碳”纳入经济社会发展和生态文明建设整体布局。同时&#xff0c;提到要把减污降碳协同增效作为促…

载誉前行!北大青鸟课工场蝉联中国高校计算机教育MOOC联盟会员单位!

近日&#xff0c;北大青鸟旗下的大学生专属品牌课工场喜获殊荣&#xff0c;蝉联中国高校计算机教育MOOC联盟会员单位。这是对北大青鸟课工场一直以来在职业教育领域的卓越表现的肯定&#xff0c;也是对北大青鸟课工场品牌价值的进一步提升。 作为中国高校计算机教育MOOC联盟的会…

JavaScript全解析-面向对象

类语法的书写 ●在 ES6 的语法标准中, 管构造函数不叫做构造函数了, 叫做 类 ●语法: class 类名 {constructor () { // 书写属性 } 书写原型上的方法 方法名 () {} } // ES6 类的语法class Person {// 等价于 ES5 的构造函数体constructor(name) {this.name name}// 直接书写…

Protobuf详解

文章目录 Protobuf是什么传输协议类比 Protobuf协议语法Protobuf类型Protobuf编译器下载配置环境变量 编写一个入门程序 Java是绝大多数人最常用的编程语言&#xff0c;那么作为Java开发如何学习protobuf呢&#xff1f; 步骤如下&#xff1a; 1.下载并安装 Protocol Buffers 工…

Red Hat Enterprise Linux (RHEL) 9.2 (x86_64, aarch64) - 红帽企业 Linux 9.2 发布

Red Hat Enterprise Linux (RHEL) 9.2 (x86_64, aarch64) 红帽企业 Linux 9.2 请访问原文链接&#xff1a;https://sysin.org/blog/rhel-9/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 红帽企业 Linux 9 红帽企业 Linux 9.…

把握协作机器人智能、灵活、安全三大矩阵

原创 | 文 BFT机器人 引言 协作机器人是一种能够和人类工作在同一空间的机器人&#xff0c;能够协同完成任务&#xff0c;为制造业和其他领域提供了更高效和灵活的解决方案。 目前&#xff0c;协作机器人市场正在迅速增长&#xff0c;因为越来越多的制造业和其他领域需要自动化…

PCIE使用的有效的命令

查看偏移内容 setpci --dumpregs capabilities查看 pci标准配置头空间 -x pci capbility配置空间 -xxx pcie扩展配置空间-xxxx 红色框框中的第一列对应具体的偏移&#xff0c;第二列对应的是设备的capability id, 第三列对应的是next capability id的偏移。 cap解释 在PCIe规…

电动车仪表盘语音芯片,带有数码管驱动多功能语音ic,WTV380-32N

为何要在电动车仪表盘上加入语音芯片&#xff1f; 电动车的驾驶过程中&#xff0c;驾驶员需要时刻关注车辆的状态和行驶信息&#xff0c;如电量、速度、里程等。这些信息如果以语音提示的方式进行播报&#xff0c;可以让驾驶员更加方便快捷地获取车辆状态&#xff0c;并且避免…

算法加密与解密、字符集、编码方式

加密算法 加密保证数据不会被窃取或者修改 不可逆加密算法 哈希算法 压缩映射&#xff1a;散列又称为哈希&#xff0c;是把任意长度的输入通过散列算法变换成固定长度的输出&#xff0c;该输出就是散列值。 哈希算法&#xff08;Hash&#xff09;又称摘要算法&#xff08;D…

相比欧美国家,国内开发软件外包项目的优势

软件开发在全球都有需求&#xff0c;尤其是欧美发达国家&#xff0c;不管是什么样的技术革命都离不开计算机软件的配套开发。另一方面欧美国家技术人员少且成本也比较高&#xff0c;相应的国内技术人员多而且技术全面&#xff0c;成本也低&#xff0c; 因此在国内找软件外包开发…

Hello, Mojo——首次体验Mojo语言

Hello, Mojo——首次体验Mojo语言 文章目录 Hello, Mojo——首次体验Mojo语言一、前言二、Mojo有哪些独特的功能使它不同于Python&#xff1f;三、可以在 Mojo 中导入和使用的 Python 哪些包&#xff1f;四、为什么参数化在 Mojo 中对于使用 SIMD 类型和硬件加速器很重要&#…

PowerShell install 一键部署TortoiseSVN

TortoiseSVN TortoiseSVN是 Subversion 版本控制系统的一个免费开源客户端&#xff0c;可以超越时间的管理文件和目录。文件保存在中央版本库&#xff0c;除了能记住文件和目录的每次修改以外&#xff0c;版本库非常像普通的文件服务器。你可以将文件恢复到过去的版本&#x…

玩机搞机--定制系统 编译系统选项 隐藏设置 关闭app联网 增加设置选项【一】

在接待一些定制rom的过程中。对于有些客户的有些要求作出对应的系统编译操作选项。例如 增减手机设置中的某些选项。 &#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&#x1f494;&am…

Druid 任意文件读取 (CVE-2021-36749)

漏洞原理 在Apache Druid系统中&#xff0c;InputSource用于从某个数据源读取数据。由于没有对用户可控的HTTP InputSource做限制&#xff0c;ApacheDruid 允许经过身份验证的用户以Druid服务器进程的权限从指定数据源读取数据&#xff0c;包括本地文件系统。攻击者可通过将文…

银河麒麟系统Arm64 编译Gdal

银河麒麟系统Arm64 编译Gdal GDAL 官网下载版本&#xff1b;我这边下载的是2.4.2 Download — GDAL documentation 拷贝到麒麟用户目录下&#xff1b;并解压 打开命令行&#xff1b;输入 make -j4 四线程编译 编译完成后输入 make install 完成后&#xff1b;此时的gdal.so会自…

windows系统下利用Nginx搭建rtmp流媒体服务器

windows系统利用Nginx搭建rtmp流媒体服务器 目录 windows系统利用Nginx搭建rtmp流媒体服务器1、介绍2、安装部署nginx3、安装部署ffmpeg实现推拉流 1、介绍 Nginx是一个高性能的HTTP和反向代理web服务器&#xff0c;并且支持rtmp&#xff0c;不过rtmp是作为一个nginx的一个模块…

DeepLab v3

Rethinking Atrous Convolution for Semantic Image Segmentation Chen L C, Papandreou G, Schroff F, et al. Rethinking atrous convolution for semantic image segmentation[J]. arXiv preprint arXiv:1706.05587, 2017. 重新思考空洞卷积用于语义图像分割 摘要 在本工作…