ReentrantLock可重入锁又是怎么回事?

news/2024/9/15 18:52:05/ 标签: java, 开发语言

前言:有关Synchronized锁的知识可以参考我上篇写的内容synchronized必知必会的知识点


一:ReentrantLock的实现原理

锁的实现原理基本是为了达到一个目的:让所有的线程都能看到某种标记。Synchronized通过在对象头中设置标记实现了这一目的,是一种/原生的锁实现方式,而ReentrantLock以及所有的基于LocK接口的实现类,都是通过用一个volitle修饰的int型变量,并保证每个线程都能拥有对该int的可见性和原子修改,其本质是基于所谓的AQS框架。

二:AQS框架又是怎么回事 

AQS (AbstractQueuedsynchronizer类)是一个用来构建铁和同步器的框架,各种LocK包中的锁(常用的有ReentrantLock、ReadWriteLock),以及其他如Semaphore,CountDownLatch,甚至是早期的FutureTask等,都是基于AQS来构建

1.AQS在内部定义了一个volatile int state变量,表示同步状态:当线程调用lock方法时,如果state=0,说明没有任何线程占有共享资源的锁,可以获得锁并将state=1;如果state=1,则说明有线程目前正在使用共享变量,其他线程必须加入同步队列进行等待。

2.AOS通过Node内部类构成的一个双向链表结构的同步队列,来完成线程获取锁的排队工作,当有线程获取锁失败后,就被添加到队列未尾。Node类是对要访问同步代码的线程的封装,包含了线程本身及其状态叫waitstatus(有五种不同取值,分别表示是否被呾塞,是否等待唤醒,是否已经被取消等),每个Node结点关联其prev结点和next结点,方便线程释放锁后快速唤醒下一个在等待的线程,是一个FIFO的过程。Node类有两个常量,SHARED和EXCLUSIVE,分别代表共享模式和独占模式。所谓共享模式是一个锁允许多条线程同时操作(信号量Semaphore就是基AQS的共享模式实现的),独占模式是同一个时间段只能有一个线程对共享资源进行操作,多余的请求线程需要排队等待(如ReentranLock)。

3.AOS通过内部类ConditionObiect构建等待队列(可有多个,当Condition调用walt0万法后,线程将会加入等待以列中,而当Condition调用signa0万法后,线程将从等待队列转移动同步队列中进行锁竞争。

4.AQS和Condition各自维护了不同的队列,在使用Lock和Condition的时候,其实就是两个队列的互相移动。

三:Synchronized和ReentrantLock二者有什么区别 

ReentrantLock是Lock的实现类,是一个互斥的同步锁。
从功能角度,Reentrantlock比synchronized的同步操作更精细(因为可以像普通对象一样使用),甚至实现Synchronized没有的高级功能

1.等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,对处理执行时间非常长的同步块很有用。口带超时的获取钡尝试。
在指定的时间范围内获取锁,如果时间到了仍然无法获取则返回。

2.可以判断是否有线程在排队等待获取锁。3.可以响应中断清求:与Synchronized不同,当获取到锁的线程被中断时,能够响应中断,中断异常将会被抛出,同时锁会被释放。4.可以实现公平锁。从锁释放角度,Synchronized在IVM层面上实现的,不但可以通过一些监控工具监控Synchronized的锁定,而且在代码执行出现异常
时,JVM会自动释放锁定;
但是使用Lock则不行,Lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally中。从性能角度,Synchronized早期实现比较低效,对比ReentrantLock,大多数场景性能都相差较大。但是在Java6中对其进行了非常多的改进,在竞争不激烈时,Svnchronized的性能要优于ReetrantLock:在高竞争情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。

四:ReentrantLock是如何实现可重入锁的

Reentrant Lock内部自定义了同步器Sync(Sync既实现了AQS,又实现了AOS,而AOS提供了一种互斥锁持有的方式)
其实就是加锁的时候通过CAS算法,将线程对象放到一个双向链表中,每次获取锁的时候,看下当前维护的那个线程ID和当前请求的线程ID是否一样一样就可重入 

五:JUC还有哪些其他的并发工具

同步器:
提供了CountDownLatch、CycicBarrier、Semaphore等,比Synchronized更加高级,可以实现更加丰富多线程操作的同步结构。

容器:
提供了ConcurrentHashMap、有序的ConcunrrentskipListMap,或者通过类似快照机制实现线程安全的动态数组CopyOnWriteArayList等,各种线程安全的容器。

并发队列:
提供了ArrayBlockingQueue、synchorousQueue或针对特定场景的PriorityBlockingQueue等,各种并发队列实现

Executor框架
可以创建各种不同类型的线程池,调度任务运行等

六:JUC中的同步器有哪些

 JUC中的同步器三个主要的成员:CountDownLatch、CyclicBarrier和Semaphore,通过它们可以方便地实现很多线程之间协作的功能。CountDownLatch叫倒计数,允许一个或多个线程等待某些操作完成。看几个场景:
模拟并发,我需要启动100个线程去同时访问某一个地址,我希望它们能同时并发,而不是一个一个的去执行。
用法:CountDownLatch构造方法指明计数数量,被等待线程调用countDown将计数器减1,等待线程使用await进行线程等待。

CyclicBarrier叫循环栅栏,它实现让一组线程等待至某个状态之后再全部同时执行,而且当所有等待线程被释放后,CyclicBarier可以被重复使用。CyclicBarier的典型应用场景是用来等待并发线程结束,CyclicBarier的主要方法是await(0,await0每被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此CyclicBarier上面阻塞的线程开始运行。在这之后,如果再次调用await0,计数就又会变成N-1,新一轮重新开始,这便是Cyclic的含义所在。CyclicBarrier.await0)带有返回值,用来表示当前线程是第几个到达这个Barrier的线程,

Semaphore,ava版本的信号量实现,用于控制同时访问的线程个数,来达到限制涌用资源访问的日的,其原理是涌过acquire0获取一个许可,如果没有就等待,而release0释放一个许可。如果Semaphore的数值被初始化为1,那么一个线程就可以通过acquire进入豆斥状态,本质上和互斥锁是非常相似的。

但是区别也非常明显,比如互斥锁是有持有者的,而对于Semaphore这种计数器结构,虽然有类似功能,但其实不存在真正意义的持有者,除非我们进行扩展包装。

七:CountDownLatch和CyclicBarrier有什么区别

它们的行为有一定相似度,区别主要在于
1.CountDownLatch是不可以重置的,所以无法重用,CyclicBarrier没有这种限制,可以重用
2.CountDownLatch的基本操作组合是countDown/await,调用await的线程阻塞等待countDown足够的次数,不管你是在一个线程还是多个线程里countDown,只要次数足够即可,
CyclicBarrier的基本操作组合就是await,当所有的伙伴都调用了await,才会继续进行任务,并自动进行重置。CountDownLatch目的是让一个线程等待基他N个线程达到某个条件后,自己再去做某个事(通过CvcicBarier的第二个构造方法publicCyclicBarrier(intparties,RunnablebarrierAction),在新线程里做事可以达到同样的效果)而CycicBarier的目的是让N多线程互相等待直到所有的都达到某个状态,然后这N个线程再继续执行各自后续(通过CountDownlatch在某些场合也能完成类似的效果) 


http://www.ppmy.cn/news/1520738.html

相关文章

MFC工控项目实例之十添加系统测试对话框

承接专栏《MFC工控项目实例之九选择下拉菜单主界面文本框显示菜单名》 参考前期我的博客文章《MFC3d立体按钮制作》 这里只给出相关代码 1、在SysTest.h文件中添加代码 #include "ShadeButtonST.h" #include "BtnST.h" class CSysTest : public CDialog {…

H5手机端调起支付宝app支付

1.调起APP页面如下 步骤 1.让后端对接一下以下文档(手机网站支付通过alipays协议唤起支付宝APP) https://opendocs.alipay.com/open/203/107091?pathHash45006f4f&refapi 2.后端接口会返回一个form提交表单 html:在页面中定义一个d…

C++学习笔记(3)

101、从结构体到类 对面向对象编程来说,一切都是对象,对象用类来描述。 类把对象的数据和操作数据的方法作为一个整体考虑。 定义类的语法: class 类名 { public: 成员一的数据类型 成员名一; 成员二的数据类型 成员名二; 成员三的数据类型 成…

安防监控视频平台LntonAIServer视频智能分析平台新增视频质量诊断功能

随着安防行业的快速发展,视频监控系统已经成为维护公共安全和个人隐私的重要工具。然而,由于各种因素的影响,视频流的质量可能会受到影响,从而导致监控效果不佳。为了解决这一问题,LntonAIServer推出了全新的视频质量诊…

「邀您参会」9月20日 中国可观测日成都站

随着首届中国可观测日上海站的圆满落幕,中国站第二站将于 9 月 20 日在成都盛大开启。在此,我们诚挚邀请您参与这场专注于监控观测领域的技术交流盛会,与行业精英共同探讨可观测性技术的前沿趋势和实践应用。 活动亮点 1、技术交流盛宴&…

什么是rest参数?

Rest参数是JavaScript中的一种特殊参数类型,也称为剩余参数或可变参数,它允许开发者定义一个函数,以便接收不定数量的参数。Rest参数的使用是通过在参数列表末尾添加...符号来实现的,这些额外的参数会被收集到一个数组中&#xff…

Docker 容器编排之 Docker Compose

目录 1 Docker Compose 概述 1.1 主要功能 1.2 工作原理 1.3 Docker Compose 中的管理层 2 Docker Compose 的常用命令参数 2.1 服务管理 2.1.1 docker-compose up : 2.1.2 docker-compose down : 2.1.3 docker-compose start : 2.1.4 docker…

【Qt的TS文件转换器】利用Python实现自动化TS文件转换

TS 文件转换器 在开发多语言Qt应用时,管理和更新翻译文件是一项繁琐但必要的任务。这个工具旨在自动化Qt Linguist TS文件的转换过程,支持不同语言之间的转换,特别关注中文变体和其他语言。 目录 🌎背景⭐特性🔒前提条…

go常用代码

连接阿波罗: 默认properties类型 package mainimport ("fmt""github.com/apolloconfig/agollo/v4""github.com/apolloconfig/agollo/v4/env/config" )func main() {c : &config.AppConfig{AppID: "2222",Cl…

在WordPress中使用AI的实用方法:专家级

在WordPress中使用AI的实用方法:专家级 随着人工智能(AI)技术的迅速发展,越来越多的网站管理员开始在WordPress中利用AI工具来提升网站的功能和用户体验。除了基础和进阶的应用之外,还有一些更高级的方法可以帮助你解…

c# json使用

安装包 用NuGet安装包:Newtonsoft.Json 对象转为Json字符串 public class Person {public string Name { get; set; }public int Age { get; set; } }Person person new Person { Name "John Doe", Age 30 }; string json2 JsonConvert.SerializeO…

免费批量Excel文件合并、拆分软件

软件介绍 下载地址:https://pan.quark.cn/s/ae860a4e2ccb 1.多个XLS或XLSX格式EXCEL文件合并,合并后可使用数据透视表进行相关操作。 2.自动合并多个EXCEL文件的第一个工作表,并汇总成一张表,可根据所有列标题需要指定需要的列。 …

LeetCode491 非递减子序列

前言 题目&#xff1a; 491. 非递减子序列 文档&#xff1a; 代码随想录——非递减子序列 编程语言&#xff1a; C 解题状态&#xff1a; 好难… 思路 注意不能对原数组进行排序。 代码 class Solution { private:vector<vector<int>> res;vector<int> pa…

2、Typescript学习——Typescript中的数组操作

1、Typescript怎样往原数组中添加多个元素 在TypeScript中&#xff0c;你可以使用数组的push方法来添加单个元素&#xff0c;或者使用扩展运算符...来添加多个元素。 let numbers: number[] [1, 2, 3]; numbers.push(4); // 添加单个元素 添加多个元素示例&#xff1a; le…

Scrapy添加代理IP池:自动化爬虫的秘密武器

在网络爬虫的世界里&#xff0c;IP地址的频繁更换是防止被目标网站封禁的有效手段。通过在Scrapy中添加代理IP池&#xff0c;你可以轻松实现自动化的IP切换&#xff0c;提高数据抓取的效率和稳定性。今天&#xff0c;我们就来详细讲解一下如何在Scrapy中添加代理IP池&#xff0…

004、架构_详解(重点)

GoldenDB 分布式数据库框架 DN和RDB增加了备节点;引入新模块CM,且GTM、MDS、PM、CM都增加备节点;MDS、PM、CM、RDB被统一在了管理节点之中;GTM和MDS间多了一条连线,因为GTM的切换由MDS把控;初步系统架构mysqld:一般称为DB节点,负责单个节点的数据处理; dbproxy:一般…

一文解析新手玩转TikTok只需TK引流系统

大家好&#xff01;今天我们就来聊一聊新手如何做Tiktok&#xff0c;以及为什么需要TK防关联引流系统。新手入门Tiktok的几大步骤 了解平台与受众&#xff1a; 首先&#xff0c;深入了解Tiktok的平台特性和用户群体的喜好。观察热门视频&#xff0c;分析它们的成功之外&#xf…

图像数据处理24

六、 图像分割 6.1阈值分割 6.1.1阙值分割的基本概念 根据图像的灰度值来对图像进行分割&#xff0c;高于灰度值的常被认为是前景图像&#xff0c;而低于灰度值的则被认为是背景图像。阙值的设定并不是唯一的&#xff0c;在对灰度图像进行阙值分割时可以设置多个阙值。 6.1…

Python画笔案例-031 绘制器形图

1、绘制蝌蚪 通过 python 的turtle 库绘制器形图&#xff0c;如下图&#xff1a; 2、实现代码 绘制器形图&#xff0c;以下为实现代码&#xff1a; """器形图.py采用前进&#xff0c;倒退&#xff0c;左转&#xff0c;右转命令制作的一个图形。 ""&q…

git clone 别人的项目上传到自己的Gitee或者github仓库

git clone别人的项目 git clone https://github.com/wohuweixiya/yft-design.git 进入该项目内&#xff0c;删除原有的.git信息 rm -r .git 初始化.git git init 将本地代码添加到仓库 git add . git commit -m "提交仓库说明" Github上新建一个和这个clone下来…