提升--22---ReentrantReadWriteLock读写锁

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • ReadWriteLock----读写锁
    • 1.读写锁介绍
    • 线程进入读锁的前提条件:
    • 线程进入写锁的前提条件:
    • 而读写锁有以下三个重要的特性:
  • ReentrantReadWriteLock的使用
        • 10、ReentrantReadWriteLock读写锁出现的目的?
        • 11、ReentrantReadWriteLock如何基于AQS实现的?


ReadWriteLock----读写锁

1.读写锁介绍

现实中有这样一种场景

对共享资源有读和写的操作,且写操作没有读操作那么频繁(读多写少)
在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源(读读可以并发)
但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写操作了(读写,写读,写写互斥)
在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量。

针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它内部,维护了一对相关的锁,一个用于只读操作,称为读锁;一个用于写入操作,称为写锁

这个ReadWriteLock 是读写锁。读写锁的概念其实就是共享锁和排他锁,读锁就是共享锁,写锁就是排他锁

  • 读锁 —共享锁
  • 写锁 —排他锁

线程进入读锁的前提条件:

  • 没有其他线程的写锁
  • 没有写请求或者有写请求,但调用线程和持有锁的线程是同一个

线程进入写锁的前提条件:

  • 没有其他线程的读锁
  • 没有其他线程的写锁

而读写锁有以下三个重要的特性:

  1. 公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平。
  2. 可重入:读锁和写锁都支持线程重入。以读写线程为例:读线程获取读锁后,能够再次获取读锁。写线程在获取写锁之后能够再次获取写锁,同时也可以获取读锁。
  3. 锁降级:遵循获取写锁、再获取读锁最后释放写锁的次序,写锁能够降级成为读锁。

ReentrantReadWriteLock的使用

  • 我们这有两个方法,read()读一个数据,write()写一个数据。read这个数据的时候我需要你往里头传一把锁,这个传那把锁你自己定,我们可以传自己定义的全都是排他锁,也可以传读写锁里面的读锁或写锁。write的时候也需要往里面传把锁,同时需要你传一个新值,在这里值里面传一个内容。我们模拟这个操作,读的是一个int类型的值,读的时候先上锁,设置一秒钟,完了之后read over,最后解锁unlock。再下面写锁,锁定后睡1000毫秒,然后把新值给value,write over后解锁,非常简单。
  • new ReentrantReadWriteLock() 是ReadWriteLock的一种实现,在这种实现里头我又分出两把锁来,一把叫readLock,一把叫writeLock,通过他的方法readWriteLock.readLock()来拿到readLock对象,读锁我就拿到了。通过readWriteLock.writeLock()拿到writeLock对象。这两把锁在我读的时候扔进去,因此,读线程是可以一起读的,也就是说这8个线程可以一秒钟完成工作结束。所以使用读写锁效率会大大的提升。
package com.cy.month12;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class T10_TestReadWriteLock {

    private static int value;

    static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    static Lock readLock = readWriteLock.readLock();
    static Lock writeLock = readWriteLock.writeLock();

    public static void read(Lock lock) {
        try {
            lock.lock();
            Thread.sleep(1000);
            System.out.println("read over!");
            //模拟读取操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void write(Lock lock, int v) {
        try {
            lock.lock();
            Thread.sleep(1000);
            value = v;
            System.out.println("write over!");
            //模拟写操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {

        Runnable readR = ()-> read(readLock);

        Runnable writeR = ()->write(writeLock, new Random().nextInt());

        for(int i=0; i<8; i++) new Thread(readR).start();
        for(int i=0; i<2; i++) new Thread(writeR).start();
    }
}

在这里插入图片描述

10、ReentrantReadWriteLock读写锁出现的目的?

首先,读写锁能解决的,互斥锁肯定能解决,但是,互斥锁的效率可能比较低。

比如说有一个业务,平均下来,10次读操作,1次写操作。

如果用互斥锁,可以保证线程安全,但是10次读操作也需要一个一个来。

但是,读读操作没有线程安全问题。

但是只要涉及到了写操作,比如读写操作,需要保证线程安全。只要有写线程,就必须满足互斥性。

所以JUC下就提供了一个ReentrantReadWriteLock,读写锁。这个锁的特点,就是读读可以一起操作,但是只要涉及到了写操作,就必须保证互斥。

11、ReentrantReadWriteLock如何基于AQS实现的?

lock锁,无论是读锁还是写锁,都是基于state属性判断的。

state是int,占32个bit为,将高16为,作为读锁的标识,低16位,作为写锁的标识。

如果线程要拿读锁,只需要确认没有写线程在持有写锁资源,并且队列中的head.next不是写锁(解决写锁饥饿问题),就可以直接获取读锁资源。

写锁需要确保没有读线程在持有读锁,并且没有其他线程在持有写锁,写锁才能拿到锁资源。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从浅入深掌握进阶结构体(C语言)

前言 这一期我们将继续讲解结构体的知识&#xff0c;还没有看过上一期的小伙伴一定要赶紧去学习哦。 上一期&#xff0c;冲鸭&#xff01; 那么话不多说我们开始今天的学习吧&#xff01; 文章目录 1,结构体的自引用2,匿名结构体3,位段4,结构体的传参5,尾声 1,结构体的自引用 …

Docker篇之docker部署harbor仓库

一、首先需要安装docker step1&#xff1a;安装docker #1、安装yun源 yum install -y yum-utils #2、配置yum源 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 如果上面源不稳定的话&#xff0c;更换为下列的aliyun源 yu…

Redis数据结构之压缩列表

压缩列表是Redis为节约内存而开发的&#xff0c;是由一系列特殊编码的连续内存块组成的顺序型数据结构。一个压缩列表可以包含任意多个节点&#xff0c;每个节点可以保存一个字节数组或者整数值。 压缩列表构成 zlbytes: 记录整个压缩列表占用的内存字节数&#xff0c;对压缩列…

预付费用电管理系统在商场及宿舍的应用

安科瑞电气股份有限公司 上海嘉定 201801 【摘要】本文主要讨论了预付费用电管理系统软、硬件的构建方法&#xff0c;软件系统的各个模块设计&#xff0c;以及软、硬件设计过程中解决的主要问题。1联5系8电2话171微3信5同2号2 【关键词】预付费电能表硬件设计软件设计 引言 …

linux基础五:linux 系统(进程状态+进程优先级+调度和切换+环境变量)

linux 系统 一.进程状态&#xff1a;1.睡眠状态(sleep)&#xff1a;2.磁盘休眠状态(disk sleep)&#xff1a;3.停止状态(stoped --- T)&#xff1a;4.死亡状态&#xff1a;5.控制状态&#xff08;t&#xff09; 二.僵尸进程和孤儿进程&#xff1a;1.僵尸状态&#xff1a;2.孤儿…

基于51单片机风扇控制器系统设计

**单片机设计介绍&#xff0c;基于51单片机风扇控制器系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机的风扇控制器系统是一种用于控制风扇转速和温度管理的电子设备。下面是一个简单的设计介绍&#xff1a;…

Python小案例:打印10以内的素数

解析 1、利用循环控制范围&#xff08;1,100&#xff09; 2、通过循环判断素数 3、利用标记位法进行打印素数 代码 #求1——100之间的素数 for i in range(2,101):# 设置标记位is_primeNumis_primeNum Truefor j in range(2,i):if i%j 0:# print(f"{i}不是素数"…

第三方支付原理

1.什么是第三方支付 所谓第三方支付&#xff0c;就是一些和各大银行签约、并具备一定实力和信誉保障的第三方独立机构提供的交易支持平台。在通过第三方支付平台的交易中&#xff0c;买方选购商品后&#xff0c;使用第三方平台提供的账户进行货款支付&#xff0c;由第三方通知卖…

04.里氏替换原则(Liskov Substitution Principle)

暴论&#xff1a;一般的&#xff0c;如果一个富二代不想着证明自己&#xff0c;那么他一辈子都会衣食无忧。 一言 里氏替换原则想告诉我们在继承过程中会遇到什么问题&#xff0c;以及继承有哪些注意事项。 概述 这是流传较广的一个段子&#xff1a; “一个坐拥万贯家财的富二…

博客文章SEO:提升博客排名和吸引更多读者的方法来啦!

互联网发展到现在&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;一直发挥着不可替代的作用。搜索引擎的流量往往更加定向&#xff0c;来自搜索引擎的流量转化率更高&#xff0c;可以帮助企业更好地实现销售和推广目标。因此&#xff0c;通过合理的SEO策略&#xff0c;你…

Data Linked UI

DataLinkedUl是一个Unity框架,它允许您在为您的应用程序创建用户界面时实现专业的数据驱动方法。使用此资产,您可以创建灵活的基于瓦片的任意大小的复杂接口系统。 核心功能: 灵活性-允许适应和调整数据变化,允许各种结构和功能配置,而不需要对现有系统进行重大破坏。 可伸…

跨境独立站反向代购系统是什么?如何搭建?

淘宝代购是近年兴起的一种购物模式&#xff0c;是帮国外客户购买中国商品。主要是通过万邦 科技的外贸代购系统&#xff0c;把淘宝、天猫等电商平台的全站商品通过API 接入到你的网站 上&#xff0c;瞬间就可以架设一个有数亿产品的大型网上商城&#xff0c;而且可以把这些中文…

BFD多跳检测配置

定义 双向转发检测BFD&#xff08;Bidirectional Forwarding Detection&#xff09;是一种全网统一的检测机制&#xff0c;用于快速检测、监控网络中链路或者IP路由的转发连通状况。 目的 为了减小设备故障对业务的影响&#xff0c;提高网络的可靠性&#xff0c;网络设备需要…

Hadoop学习笔记(HDP)-Part.16 安装HBase

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

暂时pass的题目的学习笔记(按类型分类 ):动态规划、递归

动态规划类 学习笔记来自公众号labuladong 动态规划的一般形式就是求最值——其核心问题是穷举但动态规划的穷举有些特别&#xff0c;因为这类问题存在重叠子问题 如果暴力穷举的话效率会极其低下&#xff0c;所以需要**「备忘录」或者「DP table」**来优化穷举过程&#xff…

广州华锐视点:VR仿真实训室中控系统成为VR课堂教学必备工具

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐走进我们的生活。从游戏娱乐到医疗教育&#xff0c;VR技术的应用范围日益广泛。近年来&#xff0c;VR技术在教育领域的应用也取得了显著的成果&#xff0c;为提高教育质量和培养创新人才提供了全…

【Linux】less 命令使用

less命令 less 与 more 类似。 less是一个非常常用的文本查看工具&#xff0c;它可以用于查看任意大小的文本文件&#xff0c;支持滚动翻页、搜索、标记等功能。在本文中&#xff0c;我们将详细介绍less命令的用法、参数和实例&#xff0c;并对其背后的原理和相关技术进行简要…

Spring 的设计思想、创建和使用、Bean 作用域和生命周期

文章目录 Spring 设计思想Spring 是什么&#xff1f;什么是 IoC&#xff1f; Spring 创建和使用创建 Spring 项目注册 Bean 对象获取并使用 Bean 对象 Spring 更方便地存储和读取对象配置文件使用注解使用类注解使用方法注解 获取 Bean 对象属性注入Setter 注入构造方法注入Res…

ORACLE数据库实验总集 实验二 Oracle数据库逻辑存储结构管理

一、实验目的 &#xff08;1&#xff09;掌握 Oracle数据库表空间的管理 &#xff08;2&#xff09;掌握数据库表空间不同状态时对数据操作的影响。 二、实验要求 &#xff08;1&#xff09;分别创建永久性表空间、临时性表空间、撤销表空间 &#xff08;2&#xff09;完成表…

Vue--第六天

vuex概述&#xff1a; 组件通信感觉有点白雪。。。。。。。。。。 创建项目&#xff1a; 为了学习简介&#xff0c;先选几个&#xff0c;后续是要勾选很多的 建好后再进行组件导入 创建空仓库&#xff1a; 使用&#xff1a; 上面是store访问&#xff0c;下面是辅助函数的方式…