当前位置: 首页 > news >正文

Java多线程篇(6)——AQS之ReentrantLock

文章目录

  • 1、管程
  • 2、AQS
  • 3、ReentrantLock
    • 3.1、lock/unlock
      • 3.1.1、lock
      • 3.1.2、unlock
    • 3.2、一些思考

1、管程

什么是管程?
管理协调多个线程对共享资源的访问,是一种高级的同步机制。

有哪些管程模型?
hansen:唤醒其他线程的代码必须在当前线程的最后执行,以确保其他线程被唤醒时,当前线程已经执行完。
hoare:唤醒其他线程的代码可以在任意位置,且唤醒其他线程后,当前线程立即阻塞,当被唤醒线程执行完后,再继续执行当前线程。
mesa:唤醒其他线程的代码可以在任意位置,且被唤醒线程不会立即执行,而是加入一个队列,当当前线程执行完后,再从队列中获取并执行其他线程。(需要注意的是,由于存在时间差,所以真正执行的时候有可能已经不满足条件)

其中最常用的管程模型就是mesa,在java中实现的也是该模型。如下图是AQS的实现:
在这里插入图片描述
其实管程模型在java里的实现不止有AQS,synchronized 在jvm的底层实现像什么 cxq,entryList,waitSet也是mesa管程模型中的概念,同理object.wait()/object.notify()也是管程模型的实现。

2、AQS

所以具体什么是aqs?
aqs就是java代码对管程模型的一个抽象实现。把volatile state字段定义成共享资源,并且实现了同步等待队列和条件等待队列的入队/出队以及线程的阻塞/唤醒等公共操作,至于具体共享资源的获取/释放则交由各自实现类,不同的实现类可以定义不同的共享资源获取方式,由此可以实现公平锁/非公平锁,重入锁/不可重入锁,独占锁/共享锁等以满足不同的场景。

简单的看个印象
在这里插入图片描述

共享资源:
在这里插入图片描述
同步等待队列:
在这里插入图片描述
条件等待队列:
在这里插入图片描述
获取共享资源:
在这里插入图片描述
释放共享资源:
在这里插入图片描述
阻塞:
在这里插入图片描述
唤醒:
在这里插入图片描述

3、ReentrantLock

AQS最经典的实现莫过于 ReentrantLock。接下来看看是 ReentrantLock 如何通过AQS实现 lock/unlock 的。

3.1、lock/unlock

3.1.1、lock

AbstractQueuedSynchronizer.acquire
获取共享资源模板(aqs实现)
在这里插入图片描述

ReentrantLock .tryAcquire
共享资源获取逻辑(即ReentrantLock 自己实现的获锁方法)

在ReentrantLock中实现了公平/非公平两种获锁方式(默认为非公平)

以为非公平为例:

		@ReservedStackAccessfinal boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {//cas修改共享资源if (compareAndSetState(0, acquires)) {//修改成表示获锁成功,设置当前线程setExclusiveOwnerThread(current);return true;}}//可重入锁的实现else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}

AbstractQueuedSynchronizer.addWaiter
获锁失败后入队同步队列(aqs实现)

    private Node addWaiter(Node mode) {Node node = new Node(mode);for (;;) {Node oldTail = tail;if (oldTail != null) {//cas加入队列node.setPrevRelaxed(oldTail);if (compareAndSetTail(oldTail, node)) {oldTail.next = node;return node;}} else {//初始化队列initializeSyncQueue();}}}

AbstractQueuedSynchronizer.acquireQueued
入队后阻塞之前,根据前节点的状态进行一定次数的自旋获锁(aqs实现)

	final boolean acquireQueued(final Node node, int arg) {boolean interrupted = false;try {//这个循环保证一定会获取到锁for (;;) {final Node p = node.predecessor();//如果前一个节点是头结点,再次尝试获锁if (p == head && tryAcquire(arg)) {//如果获锁成功就出队头结点setHead(node);p.next = null;return interrupted;}//如果获锁失败或者前节点不是head的节点就根据前节点的状态来看是否需要阻塞//需要阻塞就调用 LockSupport.park() 阻塞线程if (shouldParkAfterFailedAcquire(p, node))interrupted |= parkAndCheckInterrupt();}} catch (Throwable t) {cancelAcquire(node);if (interrupted)selfInterrupt();throw t;}}private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;//如果前驱节点状态为 SIGNAL 直接返回 true 阻塞线程if (ws == Node.SIGNAL)return true;//如果前驱节点状态大于0,说明线程已被返回,剔除无用节点前驱节点if (ws > 0) {do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} //cas替换前驱节点状态为 SIGNALelse {pred.compareAndSetWaitStatus(ws, Node.SIGNAL);}return false;}private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();}

也就是说,获锁失败进入同步等待队列进行阻塞,而在实际阻塞之前会自旋再次尝试获锁。

实际上在自旋途中只有前节点是head的节点才会尝试获锁
如果前节点的 waitStatus 为 signal 则停止自旋
为避免无限自旋,自旋的同时会尝试修改前节点的状态为 signal

3.1.2、unlock

AbstractQueuedSynchronizer.release
释放共享资源模板(aqs实现)
在这里插入图片描述

h.waitStatus == 0 说明后面没有等待唤醒的节点

ReentrantLock .tryRelease
共享资源释放逻辑(即ReentrantLock 自己实现的释放锁方法)

        protected final boolean tryRelease(int releases) {int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {free = true;setExclusiveOwnerThread(null);}//直接修改state值(不需要cas或者什么操作,因为释放锁不可能有并发)setState(c);return free;}

AbstractQueuedSynchronizer.unparkSuccessor
唤醒节点(aqs实现)

private void unparkSuccessor(Node node) {//清除node节点的waitStatus,重置为0int ws = node.waitStatus;if (ws < 0)node.compareAndSetWaitStatus(ws, 0);//如果node节点的后继节点被取消或者为空,就从尾部向前遍历找到实际的未取消后继节点。Node s = node.next;if (s == null || s.waitStatus > 0) {s = null;for (Node p = tail; p != node && p != null; p = p.prev)if (p.waitStatus <= 0)s = p;}//LockSupport.unparkif (s != null)LockSupport.unpark(s.thread);}

3.2、一些思考

1、公平锁和非公锁的区别在哪?
在这里插入图片描述

2、如何实现可中断的?
在这里插入图片描述

3、如何实现可超时的?
在这里插入图片描述

4、一开始没有线程获取锁,第一获取锁的线程进来直接获锁成功返回,没有入队操作,如何唤醒后继的线程?
答:虽然获锁线程没有入队,但是如果后续有等待线程需要用到队列的话还是会new一个node用于表示之前获锁线程的(相当于之前的获锁线程入队了)。
在这里插入图片描述
5、被唤醒的节点如何出队?
在这里插入图片描述

相关文章:

Java多线程篇(6)——AQS之ReentrantLock

文章目录 1、管程2、AQS3、ReentrantLock3.1、lock/unlock3.1.1、lock3.1.2、unlock 3.2、一些思考 1、管程 什么是管程&#xff1f; 管理协调多个线程对共享资源的访问&#xff0c;是一种高级的同步机制。 有哪些管程模型&#xff1f; hansen&#xff1a;唤醒其他线程的代码…...

【计算机网络】IP协议第二讲(Mac帧、IP地址、碰撞检测、ARP协议介绍)

IP协议第二讲 1.IP和Mac帧2.碰撞检测2.1介绍2.2如何减少碰撞发生2.3MTU2.4一些补充 3.ARP协议3.1协议介绍3.2报文格式分析 1.IP和Mac帧 IP&#xff08;Internet Protocol&#xff09;和MAC&#xff08;Media Access Control&#xff09;帧是计算机网络中两个不同层次的概念&am…...

TouchGFX界面开发 | 按钮控件应用示例

按钮控件应用示例 按钮是最常见的部件之一&#xff0c;有了按钮就可以点击&#xff0c;从而响应事件&#xff0c;达到人机交互的目的。TouchGFX Designer内置了七种按钮部件&#xff1a; 下压按钮&#xff1a;能够在被释放时发送回调&#xff0c;按下和释放状态都关联了图像标…...

BSVD论文理解:Real-time Streaming Video Denoising with Bidirectional Buffers

BSVD是来自香港科技大学的一篇比较新的视频去噪论文&#xff0c;经实践&#xff0c;去噪效果不错&#xff0c;在这里分享一下对这篇论文的理解。 论文地址&#xff1a;https://arxiv.org/abs/2207.06937 代码地址&#xff1a;GitHub - ChenyangQiQi/BSVD: [ACM MM 2022] Real…...

共同见证丨酷雷曼武汉运营中心成立2周年

酷雷曼武汉运营中心2周年 全国合作商齐贺武汉公司2周年庆 2021年 作为酷雷曼辐射全国版图的又一重要据点 酷雷曼武汉运营中心 在“中国光谷”正式成立 沉浸式参观酷雷曼武汉公司 2年时间 尽管历经诸多客观因素的挑战 但后浪扬帆&#xff0c;依然交出了不斐的成绩 解决…...

一种单键开关机电路图

我们设计产品时&#xff0c;通常需要设计单键开关机功能。 单键开关机&#xff0c;通常需要单片机的两个IO完成&#xff0c;一个IO用于保持开机状态。另外&#xff0c;一个IO用于判定关机状态。 下面就是一种单键开关机电路原理图&#xff1a; 此单键开关电路已经在S2W-M02、S2…...

设计模式2、抽象工厂模式 Abstract Factory

解释说明&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定他们具体的类。 简言之&#xff0c;一个工厂可以提供创建多种相关产品的接口&#xff0c;而无需像工厂方法一样&#xff0c;为每一个产品都提供一个具体工厂 抽象工厂&#xff08;Abstra…...

C++ 32盏灯,利用进制和 与 或 进行设计

一共32盏灯&#xff0c;设计一个灯光控制系统&#xff0c;其中 台球部8盏灯 桌游区8盏灯 酒吧区8盏灯 休息区8盏灯 满足以下功能 1、能够独立控制每一盏灯 2、能够一次性打开或关闭一个区域的全部灯光 3、能够获取各个区域的灯光打开关闭情况 4、能够一次性关闭打开的灯&#x…...

Ffmpeg-(1)-安装:ubuntu系统安装Ffmpeg应用

1、下载源码压缩包 https://ffmpeg.org/download.html 点击Download Source Code下载即可 解压&#xff1a; tar -xvjf ffmpeg-snapshot.tar.bz2 得到&#xff1a;ffmpeg目录 cd ffmpeg 或者&#xff1a;直接下 wget http://www.ffmpeg.org/releases/ffmpeg-5.1.tar.gztar -zx…...

系统集成|第十一章(笔记)

目录 第十一章 项目人力资源管理11.1 项目人力资源管理的定义及有关概念11.2 主要过程11.2.1 编制项目人力资源管理计划11.2.2 组建项目团队11.2.3 建设项目团队11.2.4 管理项目团队 11.3 现代激励理论11.4 项目经理所需具备的影响力11.5 常见问题 上篇&#xff1a;第十章、质量…...

二叉树题目:二叉树剪枝

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉树剪枝 出处&#xff1a;814. 二叉树剪枝 难度 4 级 题目描述 要求 给定二叉树的根结点 root \texttt{root} root&#xff0c;返回移除了所有…...

JAVA中使用CompletableFuture进行异步编程

JAVA中使用CompletableFuture进行异步编程 1、什么是CompletableFuture CompletableFuture 是 JDK8 提供的 Future 增强类&#xff0c;CompletableFuture 异步任务执行线程池&#xff0c;默认是把异步任 务都放在 ForkJoinPool 中执行。 在这种方式中&#xff0c;主线程不会…...

uniapp:配置动态接口域名,根据图片访问速度,选择最快的接口

common.js // 动态测速选择的域名 // h5直接返回默认第一个域名 // vue文件用到域名的话用this.$baseURL let domains [{uri:192.168.31.215:9523, speed:0},{uri:api.ceshi.org, speed:0}, ]export const protocol {api: http://,//本地// api: https://api.,//正式h5Url: h…...

Lambda表达式常见用法(提高效率神器)

Java8中一个非常重要的特性就是Lambda表达式&#xff0c;我们可以把它看成是一种闭包&#xff0c;它允许把函数当做参数来使用&#xff0c;是面向函数式编程的思想&#xff0c;一定程度上可以使代码看起来更加简洁。 其实以上都不重要&#xff0c;重要的是能够提高我的开发效率…...

2023旷视自驾感知算法暑期实习一面

来源&#xff1a;投稿 作者&#xff1a;LSC 编辑&#xff1a;学姐 1. 问下项目&#xff0c;问下我的情况 2. 是否了解最新的BEV算法&#xff0c;讲一下 3. 是否了解三维重建 4. 考察相机坐标系的转换 5. 手撕代码&#xff0c;翻车了&#xff0c;不考leetcode&#xff0c;考…...

Python3 如何实现 websocket 服务?

Python 实现 websocket 服务很简单&#xff0c;有很多的三方包可以用&#xff0c;我从网上大概找到三种常用的包&#xff1a;websocket、websockets、Flask-Sockets。 但这些包很多都“年久失修”&#xff0c; 比如 websocket 在 2010 年就不维护了。 而 Flask-Sockets 也在 2…...

SQLAlchemy常用数据类型

目录 SQLAlchemy常用数据类型 代码演示 代码分析 SQLAlchemy常用数据类型 SQLAlchemy 是一个Python的SQL工具库和对象关系映射(ORM)工具&#xff0c;它提供了一种在Python中操作数据库的高效方式。下面是SQLAlchemy中常用的一些数据类型&#xff1a; Integer&#xff1a;整形&…...

Vue路由与nodejs下载安装及环境变量的配置

目录 前言 一、Vue路由 1.路由简介 是什么 作用 应用场景 2.SPA简介 SPA是什么 SPA的优点 注意事项 3.路由实现思路 1.引入路由的js依赖 2.定义组件 3.定义组件与路径的对应关系 4.通过路由关系获取路由对象router 5.将路由对象挂载到实例中 6.触发路由事…...

HarmonyOS之 应用程序页面UIAbility

一 UIAbility介绍&#xff1a; 1.1 UIAbility是一种包含用户界面的应用组件&#xff0c;主要用于和用户进行交互 1.2 UIAbility也是系统调度的单元&#xff0c;为应用提供窗口在其中绘制界面 二 UIAbility跳转和传参 2.1 页面间的导航可以通过页面路由router模块来实现。页…...

数据集笔记: Porto

数据来源&#xff1a;Taxi Trajectory Data_数据集-阿里云天池 (aliyun.com) 1 数据介绍 葡萄牙波尔图市运行的所有442辆出租车的全年轨迹&#xff08;从2013年7月1日至2014年6月30日&#xff09; 2 读取数据 import pandas as pdtrapd.read_csv(C:/Users/16000/Download…...

修改vscode底部栏背景和字体颜色

修改vscode底部栏背景和字体颜色 如图&#xff1a; 首先打开齿轮&#xff0c;打开设置搜索workbench.colorCustomizations,然后点击编辑setting.json修改setting.json内内容 "workbench.colorCustomizations": {"statusBar.foreground": "#FFFFFF…...

加速企业AI实施:成功策略和效率方法

文章目录 写在前面面临的挑战MlOps简介好书推荐 写作末尾 写在前面 作为计算机科学领域的一个关键分支&#xff0c;机器学习在当今人工智能领域中占据着至关重要的地位&#xff0c;广受瞩目。机器学习通过深入分析大规模数据并总结其中的规律&#xff0c;为我们提供了解决许多…...

【图论C++】树的重心——教父POJ 3107(链式前向星的使用)

》》》算法竞赛 /*** file * author jUicE_g2R(qq:3406291309)————彬(bin-必应)* 一个某双流一大学通信与信息专业大二在读 * * brief 一直在竞赛算法学习的路上* * copyright 2023.9* COPYRIGHT 原创技术笔记&#xff1a;转载…...

hhh百度地铁广告太搞笑了;24家国内大模型公司面经;LLM法律应用实践;AI+教育产品图谱与工作流 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f525; 会玩儿&#xff01;承包地铁专列&#xff0c;真人移动广告 | 百度世界大会预热 百度也是会玩儿&#xff01;承包了北京地铁一号线的「…...

项目管理:项目经理一定要避开这四大误区

项目经理要保质保量按时达成项目目标&#xff0c;需要关注项目的方方面面&#xff0c;要具有很强的沟通协调能力和目标意识。但是项目经理也不免不了失误&#xff0c;管理中的这四大误区&#xff0c;你经历过几个&#xff1f; 误区一&#xff1a;做不该做的事 你是否遇到这种…...

爬虫为什么需要 HTTP 代理 IP?

前言 爬虫在互联网数据采集、分析和挖掘中扮演着至关重要的角色&#xff0c;但是对于目标网站而言&#xff0c;频繁的爬虫请求可能会对其服务器产生不小的负担&#xff0c;严重的情况甚至会导致网站崩溃或者访问受限。为了避免这种情况的发生&#xff0c;同时也为了保护客户端…...

leetcode刷题笔记/代码随想录笔记——移除字符串中多余空格

1. 使用erase()函数 void removeExtraSpaces(string& s) {for (int i s.size() - 1; i > 0; i--) {if (s[i] s[i - 1] && s[i] ) {s.erase(s.begin() i);}}// 删除字符串最后面的空格if (s.size() > 0 && s[s.size() - 1] ) {s.erase(s.begi…...

dataGrip导出导入的方式

导出&#xff1a;选中需要导出的表 导入&#xff1a;选中导出的sql文件...

LeetCode279. 完全平方数

279. 完全平方数 文章目录 [279. 完全平方数](https://leetcode.cn/problems/perfect-squares/)一、题目二、题解方法一&#xff1a;完全背包二维数组方法二&#xff1a;一维数组&#xff08;空间复杂度更小的改进版本,最下面的两个版本不需要存储完全平方数&#xff09; 一、题…...

【CMake】add_dependencies 命令

【CMake】add_dependencies 原文链接&#xff1a;https://blog.csdn.net/new9232/article/details/125831009 参考链接&#xff1a;https://blog.csdn.net/new9232/article/details/121374943 简介 add_dependencies(<target> [<target-dependency>]...)官方文档…...

设计师专用网站/seo网络推广知识

不是成功以后才快乐&#xff0c;而是快乐以后才成功。世界上什么都可以失去&#xff0c;就是不可以失去希望&#xff0c;世界上什么都可以失去&#xff0c;就是不可以失去信心。 ---------阳光格言 在一万多米的高空&#xff0c;一架飞机出…...

关于做公司官方网站域名申请/制作网页完整步骤代码

下面是育路教育网编辑整理2011年计算机基础知识精选部分及答案&#xff0c;供大家参考一下。祝愿所有考生考试顺利&#xff01;1.世界上第一台电子计算机诞生于 ( B)A&#xff0e; 1941年B&#xff0e; 1946年C&#xff0e; 1949年D&#xff0e; 1950年2. 世界上首次提出存储程…...

emlog做企业网站/云服务器免费

Prelude 为什么洛谷上的题解都是剪枝做的啊&#xff01;就没有人写复杂度靠谱的算法吗&#xff01; 传送到洛谷&#xff1a;(&#xffe3;、&#xffe3;) 传送到BZOJ&#xff1a;( &#xff65;&#xff65;)&#xff89;(._.) 本篇博客地址&#xff1a;o(><&#xff1b…...

php做的网站怎么加密/百度seo排名优化公司

Linux中的配置文件一般为&#xff1a;纯文本格式 XML格式Bash配置文件&#xff1a;1&#xff09; profile类&#xff1a;交互式登录用户/etc/profile(它还包含-/etc/profile.d/*.sh对全局用户有效)--~/.bash_profile(仅对某个用户有效,编辑它还可以针对特定用户在登录时显示…...

微博带动网站做排名/seo网站建设公司

博士生的面试会有所不同么&#xff1f; ●我们会根据每个人的情况安排有针对性的面试 ●面试内容包括标准算法&#xff0c;设计&#xff0c;编码能力 ●论文讨论 ●所有的面试官都具有博士学位 Google软件工程师如是说&#xff1a; 问&#xff1a;在Google工作&#xff0c;最担…...

微信网站收钱吗/最新消息新闻头条

广东省积极推进企业改制&#xff0c;建立现代企业制度&#xff0c;企业的市场竞争能力不断提升&#xff0c;经济效益不断提高。同时&#xff0c;广东省积极利用毗邻港澳和属于沿海地区的地缘优势&#xff0c;大力发展对外贸易&#xff0c;承接外来加工贸易&#xff0c;使得全省…...