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

【并发编程】AQS原理

       📝个人主页:五敷有你      

 🔥系列专栏:并发编程

⛺️稳中求进,晒太阳

1. 概述

全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架

特点:

  • 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
    • getState - 获取 state 状态
    • setState - 设置 state 状态
    • compareAndSetState - cas 机制设置 state 状态
    • 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
  • 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList
  • 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet

子类主要实现这样一些方法(默认抛出 UnsupportedOperationException)

  • tryAcquire
  • tryRelease
  • tryAcquireShared
  • tryReleaseShared
  • isHeldExclusively

获取锁的姿势

// 如果获取锁失败
if (!tryAcquire(arg)) { 
// 入队, 可以选择阻塞当前线程 park unpark
}

释放锁的姿势

// 如果释放锁成功
if (tryRelease(arg)) { 
// 让阻塞线程恢复运行
}

2. 实现不可重入锁

自定义同步器

//同步器类
class MySync extends AbstractQueuedSynchronizer {@Overrideprotected boolean tryAcquire(int arg) {if (compareAndSetState(0,1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}@Overrideprotected boolean tryRelease(int arg) {setExclusiveOwnerThread(null);setState(0);return true;}@Override //是否持有独占锁protected boolean isHeldExclusively() {if(getExclusiveOwnerThread()!=null){return true;}return false;}public Condition newCondition(){return  new ConditionObject();}}

自定义锁

有了自定义同步器,很容易复用 AQS ,实现一个功能完备的自定义锁

public class MyLock implements Lock {MySync mySync=new MySync();@Override  //加锁,不成功进入等待队列等待
public void lock() {mySync.acquire(1);}@Override //加锁,可以被打断
public void lockInterruptibly() throws InterruptedException {mySync.acquireInterruptibly(1);
}@Override //尝试加锁(一次)
public boolean tryLock() {mySync.tryAcquire(1);return true;
}@Override //尝试加锁(带超时时间)
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {mySync.tryAcquireNanos(1,unit.toNanos(time));return true;
}@Override //解锁
public void unlock() {mySync.release(1);
}@Override  //创建条件变量
public Condition newCondition() {return mySync.newCondition();
}}

测试一下

public static void main(String[] args) {Lock myLock=new MyLock();new Thread(()->{myLock.lock();try {System.out.println("locking...");Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}finally {System.out.println("unlock...");myLock.unlock();}},"t1").start();new Thread(()->{myLock.lock();try {System.out.println("加锁...");}finally {System.out.println("解锁...");myLock.unlock();}},"t2").start();}

心得

起源

早期程序员会自己通过一种同步器去实现另一种相近的同步器,例如用可重入锁去实现信号量,或反之。这显然不够优雅,于是在 JSR166(java 规范提案)中创建了 AQS,提供了这种通用的同步器机制。

目标

AQS 要实现的功能目标

  • 阻塞版本获取锁 acquire 和非阻塞的版本尝试获取锁 tryAcquire
  • 获取锁超时机制
  • 通过打断取消机制
  • 独占机制及共享机制
  • 条件不满足时的等待机制

设计

AQS 的基本思想其实很简单

获取锁的逻辑

while(state 状态不允许获取) {if(队列中还没有此线程) { 入队并阻塞 }}当前线程出队

释放锁的逻辑

if(state 状态允许了) {恢复阻塞的线程(s)}

要点

  • 原子维护 state 状态
  • 阻塞及恢复线程
  • 维护队列
1) state 设计
  • state 使用 volatile 配合 cas 保证其修改时的原子性
  • state 使用了 32bit int 来维护同步状态,因为当时使用 long 在很多平台下测试的结果并不理想
2) 阻塞恢复设计
  • 早期的控制线程暂停和恢复的 api 有 suspend 和 resume,但它们是不可用的,因为如果先调用的 resume那么 suspend 将感知不到
  • 解决方法是使用 park & unpark 来实现线程的暂停和恢复,具体原理在之前讲过了,先 unpark 再 park 也没问题
  • park & unpark 是针对线程的,而不是针对同步器的,因此控制粒度更为精细
  • park 线程还可以通过 interrupt 打断
3) 队列设计
  • 使用了 FIFO 先入先出队列,并不支持优先级队列
  • 设计时借鉴了 CLH 队列,它是一种单向无锁队列

主要用到AQS的并发工具类

相关文章:

【并发编程】AQS原理

📝个人主页:五敷有你 🔥系列专栏:并发编程 ⛺️稳中求进,晒太阳 1. 概述 全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架 特点: 用 state 属性来表示资源的状…...

AI:130-基于深度学习的室内导航与定位

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…...

Leetcode1423.可获得的最大点数

文章目录 题目原题链接思路(逆向思维) 题目 原题链接 Leetcode1423.可获得的最大点数 思路(逆向思维) 由题目可知,从两侧选k张,总数为n张,即从中间选n - k张 nums总和固定,要选k张最…...

深度学习之梯度下降算法

梯度下降算法 梯度下降算法数学公式结果 梯度下降算法存在的问题随机梯度下降算法 梯度下降算法 数学公式 这里案例是用梯度下降算法,来计算 y w * x 先计算出梯度,再进行梯度的更新 import numpy as np import matplotlib.pyplot as pltx_data [1.0,…...

代码随想录第32天|● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

文章目录 买卖股票思路一:贪心代码: 思路:动态规划代码: 跳跃游戏思路:贪心找最大范围代码: 跳跃游戏②思路:代码: 方法二:处理方法一的特殊情况 买卖股票 思路一&#x…...

线性代数的本质 2 线性组合、张成的空间、基

基于3Blue1Brown视频的笔记 一种新的看待方式 对于一个向量,比如说,如何看待其中的3和-2? 一开始,我们往往将其看作长度(从向量的首走到尾部,分别在x和y上走的长度)。 在有了数乘后&#xff0…...

- 工程实践 - 《QPS百万级的有状态服务实践》01 - 存储选型实践

本文属于专栏《构建工业级QPS百万级服务》 《QPS百万级的无状态服务实践》已经完成。截止目前为止,支持需求“给系统传入两个日期,计算间隔有多少天”的QPS百万级服务架构已经完成。如图1: 图1 可是这个架构不能满足需求“给系统传入两个日期…...

SECS/GEM的HSMS通讯?金南瓜方案

High Speed SECS Message Service (HSMS) 是一种基于 TCP/IP 的协议,它使得 SECS 消息通信更加快速。这通常用作设备间通信的接口。 HSMS 状态逻辑变化(序列): 1.Not Connected:准备初始化 TCP/IP 连接,但尚…...

wayland(xdg_wm_base) + egl + opengles——dma_buf 作为纹理数据源(五)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、EGL dma_buf import 相关的数据结构和函数1. EGLImageKHR2. eglCreateImageKHR()3. glEGLImageTargetTexture2DOES()二、egl 中 import dma_buf 作为纹理的代码实例1. egl_wayland_dmabuf_…...

【VTKExamples::PolyData】第二十八期 LinearExtrusion

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例LinearExtrusion,并解析接口vtkLinearExtrusionFilter,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 目录…...

Linux操作系统基础(五):Linux的目录结构

文章目录 Linux的目录结构 一、Linux目录与Windows目录区别 二、常见目录介绍(记住重点) Linux的目录结构 一、Linux目录与Windows目录区别 Linux的目录结构是一个树型结构 Windows 系统 可以拥有多个盘符, 如 C盘、D盘、E盘 Linux 没有盘符 这个概…...

SolidWorks如何在一个零件的基础上绘制另一个零件

经过测试,新建零件,然后插入零件a,在a的基础上绘制b,这种做法无法断开a与b的联系。虽然可以通过切除命令,切除b,但不是正途。 在装配体中可以实现: (1)建立装配体 (2&…...

gin(结)

gin day1 今天的目标就是学懂,看懂每一步代码。 gin框架 gin框架就是go语言的web框架。框架你也可以理解成一个库。里面有一堆封装好的工具,帮你实现各种各样的功能,这样使得你可以关注业务本身,而在写代码上少费力。 快速入门&…...

JavaScript 设计模式之桥接模式

桥接模式 通过桥接模式,我们可以将业务逻辑与元素的事件解耦,也可以更灵活的创建一些对象 倘若我们有如下代码 const dom document.getElementById(#test)// 鼠标移入移出事件 // 鼠标移入时改变背景色和字体颜色 dom.onmouseenter function() { th…...

B3651 [语言月赛202208] 数组调整

题目描述 给出一个长度为 n 的数组,第 i 个数为ai​。 为了调整这个数组,需要将第 k 个数改变为 −ak​。 请你求出调整后的数组中所有数的和。 输入格式 输入共两行。 输入的第一行为两个整数 n,k。 输入的第二行为 n 个整数,第 i 个…...

MessageQueue --- RabbitMQ

MessageQueue --- RabbitMQ RabbitMQ IntroRabbitMQ 核心概念RabbitMQ 分发类型Dead letter (死信)保证消息的可靠传递 RabbitMQ Intro 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,…...

WordPress作者页面链接的用户名自动变成16位字符串串插件Smart User Slug Hider

WordPress默认的作者页面URL链接地址格式为“你的域名/author/admin”,其中admin就是你的用户名,这样的话就会暴露我们的用户名。 为了解决这个问题,前面boke112百科跟大家分享了『如何将WordPress作者存档链接中的用户名改为昵称或ID』一文…...

Nvidia 携手 RTX 推出的本地运行 AI 聊天机器人

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

年假作业day2

1.打印字母图形 #include<stdio.h> #include<string.h> int main(int argc, const char *argv[]) { int i,j; char k; for(i1;i<7;i) { for(j1;j<i;j) { printf("%c",_); } for(j0,…...

HTML-多媒体嵌入-MDN文档学习笔记

HTML-多媒体与嵌入 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever MDN中文官网 HTML-中的图片 将图片放入网页 可以使用<img/>来将图片嵌入网页&#xff0c;它是一个空元素&#xff0c;最少只需src属性即可工作 <img src"图片链接"…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...