ReentrantReadWriteLock可重入读写锁

news2025/1/10 21:24:30

目录

读写锁:

 锁降级

锁饥饿:       


读写锁:

        定义:一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程

    特点:读写互斥,写锁独占,读读可共享,读没有完成的时候其它线程写锁无法获得
public class ReentrantReadWriteLockDemo1 {
    public static void main(String[] args) {
        MyResource myResource = new MyResource();
        for (int i = 0; i < 10; i++) {
            String finalI1 = String.valueOf(i);
            new Thread(() -> {
                myResource.write(finalI1, finalI1);
            }, String.valueOf(i)).start();
        }
        for (int i = 0; i < 10; i++) {
            String finalI = String.valueOf(i);
            new Thread(() -> {
                myResource.read(finalI);
            }, String.valueOf(i)).start();
        }

        try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
        for (int i = 0; i < 3; i++) {
            String finalI = String.valueOf(i);
            new Thread(()->{
                myResource.write("新的写锁"+finalI,finalI);
            },String.valueOf(i)).start();
        }
    }
}

class MyResource {
    Map<String, Object> map = new HashMap<>();

    Lock lock = new ReentrantLock();

    ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    public void write(String key, String value) {
        reentrantReadWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "写锁正在写入");
            map.put(key, value);
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" +"写入完成");
        } finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }

    public void read(String key) {
        reentrantReadWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "读锁正在读取");
            Object o = map.get(key);
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" +"读取完成"+"\t"+String.valueOf(o));
        } finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }
}

必须等到读锁读完资源,新的写锁才能获取,继续写入

 锁降级

        如果同一个线程持有了写锁,在没有释放写锁的情况下,它还可以继续获取读锁。这就是写锁的降级,降级成为了读锁。

        写锁降级的次序策略:

        遵循获得写锁---》再获取读锁---》再释放写锁的次序,写锁能降级成为读锁。 

        相当于同一个线程自己持有写锁时再去拿读锁,其本质是重入锁。

示例:

   public static void main(String[] args) {
        ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock readLock =  reentrantReadWriteLock.readLock();
        ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();


        writeLock.lock();
        System.out.println("先写入");

        readLock.lock();
        System.out.println("后读取");

        writeLock.unlock();

        readLock.unlock();
    }

 

 遵循锁降级次序策略:先获取写锁-再获取读锁--在释放写锁,没有阻塞正常释放锁结束。

反之:

/**
 * 锁降级
 */
public class LockDownGradingDemo2 {
    public static void main(String[] args) {
        ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock readLock =  reentrantReadWriteLock.readLock();
        ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();


        readLock.lock();
        System.out.println("先读取");

        writeLock.lock();
        System.out.println("后写入");

        writeLock.unlock();

        readLock.unlock();
    }
}

 先获取读锁,则一直阻塞,不能获取写锁。必须等到读锁释放锁后,获取写锁。可以理解为看了一半复联4,突然电影被改成上海堡垒,显然是不可接受的。

锁饥饿:       

          因为读的线程特别多,而且读写锁中的读锁是一种悲观锁,没有读完是不会释放的,所以会造成写锁长时间获取不到锁,出现锁饥饿的现象。

        假设有1000个线程,其中读锁999个,写锁1个,每个读锁要读取10s,这样会造成写锁一直抢不到锁的情况,出现锁饥饿的问题。

       

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

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

相关文章

分布式学习第三天—远程调用和网关

Feign远程调用 Feign的介绍 Feign是一个声明式的http客户端&#xff0c;官方地址&#xff1a;https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现http请求的发送 Feign远程调用的使用步骤 1.引入依赖 在子模型服务的pom文件中引入feign的依赖&#xff1a; &l…

【计网】入门知识

一些基本认识网络传输基本要素&#xff1a;网络编程&#xff1a;python的网络编程方式TCP和UDP一些编程技巧socket实现TCP通信网络传输基本要素&#xff1a; 有连接通道、传输字节数据、输入输出遵守一样的协议 网络编程&#xff1a; CS&#xff08;QQ下载客户端&#xff09…

linux防火墙究竟如何使用?iptables的原理与简单应用

1. 什么是防火墙&#xff1f; 在计算机体系中&#xff0c;防火墙是基于预定安全规则来监视和控制传入和传出网络流量的网络安全系统。该计算机流入流出的所有网络通信均要经过此防火墙。防火墙对流经它的网络通信进行扫描&#xff0c;这样能够过滤掉一些攻击&#xff0c;以免其…

Vulkan 理解Vertex Input Description

此文为个人记录&#xff0c;感兴趣直接看https://zhuanlan.zhihu.com/p/450157594 首先&#xff0c;一个顶点的结构体 struct Vertex {glm::vec3 pos;glm::vec3 color; }CPU端给出顶点数据 const std::vector<Vertex> vertices {{{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}},…

Allegro如何显示盲埋孔钻孔所在层面操作指导

Allegro如何显示盲埋孔钻孔所在层面操作指导 在用Allegro做PCB设计的时候,涉及盲埋孔设计的时候,需要实时看到盲埋孔是打在哪层到哪层,如下图 实时显示了盲埋孔是从哪层到哪层的,比如1-3,3-6等等 如何显示,具体操作如下 选择Setup选择design Parameters

[golang Web开发] 3.golang web开发:处理请求

简介 Go语音的net/http包提供了一系列用于表示HTTP报文的结构,可以使用它处理请求和发送响应,其中Request结构代表了客户端发送的请求报文,下面是Request讲解 type Request struct {// Method指定HTTP方法&#xff08;GET、POST、PUT等&#xff09;。对客户端&#xff0c;"…

linux系统加固

linux安全加固 linux系统安全包括用户安全、权限安全、文件安全 从那些方面进行加固 身份鉴别 访问控制 安全审计 资源控制 入侵防范 在linux当中一切皆文件 身份鉴别 /etc/login.defs 文件功能 查看密码策略 /etc/login.defs文件定义了与/etc/passwd和/etc/shadow配套的用户限…

VOIP创建

一、介绍VOIP的推送证书的创建方式和普通的证书的创建方式基本一致。二、步骤首先需要生成证书签名的请求文件CerSingingRequest&#xff0c;打开钥匙串应用&#xff0c;点击钥匙串访问->证书助理->从证书颁发机构请求输入电子邮件和名称后保存到本地3.在developer.apple…

服务器防火墙 配置端口号

作为前端的我头次做运维的事情。 现在服务器是的默认端口好像只有80&#xff0c;443&#xff0c;其余端口都需要我们配置 域ping 通了&#xff0c;以为服务配置好了可以撸起袖子加油干&#xff0c;但是 访问公司的服务 出错了400 访问公司的服务xxx.168.30.xxx:8081&#xff…

【字符串】leetcode344.反转字符串(C/C++/Java/Python/Js)

leetcode344.反转字符串1 题目2 思路3 代码3.1 C版本3.2 C版本3.3 Java版本3.4 Python版本3.5 JavaScript版本4 总结打基础的时候&#xff0c;不要太迷恋于库函数。 1 题目 题源链接 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给…

国内最新餐饮品牌全案设计十大排名(2023年榜单)

餐饮全案设计是餐饮店经营过程之前的重要一步&#xff0c;想要打造一家特色餐饮店并不是一件简单的事。一来要满足功能性需求的同时还具有一定的审美性&#xff1b;二来既要尽可能高地提升空间利用率让顾客消费体验愉悦和服务员工作效率高&#xff0c;能够展现餐厅的主题和文化…

分布式锁原理及Redis如何实现分布式锁

一淘模板给大家带来了关于redis的相关知识&#xff0c;其中主要介绍了关于分布式锁是什么&#xff1f;Redis又是怎么实现分布式锁的&#xff1f;需要满足什么条件&#xff1f;下面一起来看一下吧&#xff0c;希望对需要的朋友有帮助。 一、分布式锁基本原理 分布式锁&#xff…

PTA L1-027 出租(详解)

前言&#xff1a;本期是关于出租的详解&#xff0c;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读&#xff0c;今天你c了吗&#xff1f; 题目&#xff1a; 下面是新浪微博上曾经很火的一张图&#xff1a; 一时间网上一片求救…

【python学习笔记】:数据科学库操作(三)

接上一篇&#xff1a; 14、Pandas Pandas 是一个快速、强大、灵活且易于使用的开源数据分析和操作工具&#xff0c; Pandas 可以从各种文件格式比如 CSV、JSON、SQL、Microsoft Excel 导入数据&#xff0c;可以对各种数据进行运算操作&#xff0c;比如归并、再成形、选择&#…

SockJS-client简介

概述 SockJS是一个浏览器JavaScript库&#xff0c;提供了一个类似websocket的对象。SockJS为您提供了一个连贯的&#xff0c;跨浏览器的Javascript API&#xff0c;它在浏览器和web服务器之间创建了一个低延迟&#xff0c;全双工&#xff0c;跨域通信通道。 实际上&#xff0…

计算机网络入门(网络协议篇)

计算机网络分类虽然网络类型的划分标准各种各样&#xff0c;但是从地理范围划分是一种大家都认可的通用网络划分标准。按这种标准可以把各种网络类型划分为局域网、城域网、广域网三种。局域网一般来说只能是一个较小区域内&#xff0c;城域网是不同地区的网络互联&#xff0c;…

什么是进取心?如何提高进取心?

1、什么是进取心&#xff1f;进取心是一种心理状态&#xff0c;说的是积极上进&#xff0c;不断对自己提高要求&#xff0c;促使自己持续发展的心态。不论是学习还是工作&#xff0c;进取心都是我们获取成就的必备。从人的一生来说&#xff0c;进取心是我们探索人生最宝贵的修养…

ADB 开启 USB调试后,无法自动弹出调试授权窗口的解决方法

之前介绍了 Android Device Unauthorized 的解决方案&#xff0c;这次将分享 开启 USB调试后&#xff0c;无法自动弹出调试授权窗口的解决方法。即使选择在 “仅充电” 的情况下去调试&#xff0c;结果都一样。 在我自己的工程机 (荣耀系列的) 连上电脑后&#xff0c;USB 连接方…