深入理解java并发编程之aqs框架

跟synchronized 相比较,可重入锁ReentrankLock其实原理有什么不同?
所得基本原理是为了达到一个目的;就是让所有线程都能看到某种标记。synchronized通过在对象头中设置标记实现了这一目的,是一种JVM原生的锁实现方式。而ReentrantLock以及所有的基于Lock接口的实现类,都是通过一个volitile修饰的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、AQS通过Node内部类构成一个双向链表结构的同步队列,来完成线程获取锁的排队工作,当线程获取锁失败之后,就被添加到队列末尾。
Node 类是对要访问同步代码的线程的封装,包含了线程本身及其状态叫waitStatus(有五种不同取值,分别表示是否被阻塞,是否等待唤醒,是否已经被取消等),每个Node结点关联器prev结点和next结点,方便线程释放锁后快速唤醒下一个在等待的线程,是一个FIFO的过程。 - Node类有两个常量,SHARED和EXCLUSIVE,分别代表共享模式和独占模式。所谓共享模式是一个锁允许多条线程同时操作(信号量 Smaphore 就是基于AQS的共享模式实现的),独占模式是同一个时间段只能有一个线程对共享资源进行操作,多余的请求线程需要排队等待。
- 3、AQS通过内部类ConditionObject 构建等待队列(可有多个),当Condition 调用wait()方法之后,线程将会加入等待队列中,而当Condition 调用 signal()方法之后,线程将从等待队列转移到同步队列中进行锁竞争。
- 4、AQS和Condition各自维护了不同的队列,在使用Lock和Condition的时候,其实就是两个队列的互相移动。
请尽可能详细的对比一下synchronized和ReentrantLock的异同
ReentrantLock 是Lock的实现类,是一个互斥的同步锁。
从功能的角度上ReentrantLock比synchronized同步操作更加精细,甚至实现synchronized没有高级功能,例如
- 等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,对处理执行时间非常长的同步块很有用
- 带超时的获取锁尝试:在指定的时间范围内获取锁,如果时间到了仍然无法获取则返回。
- 可以判断是否有线程在排队等待获取锁。
- 可以响应中断请求:与synchronized不同,当获取到锁的线程被中断时,能够响应中断,中断异常将会被抛出,同时锁会被释放。
- 可以实现公平锁。
从锁释放酵素synchronized在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行出现异常的时候,JVM会自动释放锁定;但是使用Lock则不行,Lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally()代码中。
从性能角度上来讲,Synchronized早期实现的比较低效,对比ReentrantLock,大多数的使用场景性能都较差。但是Java 6中对其进行了很多的改进,在竞争不激烈的时候,synchronized 的性能要优于 ReentrantLock;在高竞争的情况下,synchronized的性能会下降几十倍,但是ReentrantLock的性能则不变。
ReentrantLock是如何实现可重入性的?
ReentrantLock内部自定义了同步器Sync(Sync即实现了AQS,又实现了AOS,而AOS提供了一种互斥锁持有的方式)也就是在加锁的时候使用了CAS算法,将线程对象放入到一个双向链表中,每次获取锁的时候,看一下当前维护的是那个线程ID和当前请求的线程ID是否一样,如果一样就可以获取到锁,如果不一样就无法获取到锁。
除了ReentrantLock,还有那些JUC中的并发工具?
通常所说的并发包(JUC)也就是java.util.concurrent 及其子包,集中了Java并发的各种基础工具类,具体主要包括几个方面:
- 提供了CountDownLatch、CyclicBarrier、Semaphore等等,这些都比synchronized更加高级,可以实现更加丰富的多线程控制同步结构。
- 提供了ConcurrentHashMap、有序的ConcurrentSkipListMap、或者通过类似快照机制实现线程安全的动态数组CopyOnWriteArrayList等,各种线程安全的容器。
- 提供了ArrayBlockingQueue、SynchronousQueue或者针对特定场景的PriorityBlockingQueue等等,各种并发队列实现。
- 强大的Executor框架,可以创建各种不同类型的线程池,调度任务运行等等。
请谈一谈ReadWriteLock 和 StampedLock的区别。
虽然ReentrantLock和synchronized使用简单,但是实现行为上有一定的局限性,要么不占,要么独占。实际应用场景中。有时候不需要大量竞争的写操作,而是以并发读取为主,为了进一步优化并发操作的粒度,Java提供了读写锁。
读写锁基于的原理是多个读操作不需要互斥,如果读锁试图锁定时,写锁是被某个线程持有,读锁将无法获取,而只好等待对方操作结束,这样就可以自动保证不会读取到有争议的数据。
ReadWriteLock代表了一对锁,下图是一个基于读写锁实现的数据结构,当数据量较大,并发读多,并发写少的时候。能够比纯同步版本凸显出优势。

读写锁看起来比synchronized的粒度似乎更细一些,但在实际应用中,其表现也不是太好。主要还是因为相对比较大的开销。
所以JDK在后期又引入了StampedLock,在提供类似读写锁的同时,还支持优化读模式,优化读基于假设,大多数情况下读操作并不会和写操作冲突,其逻辑是先试着修改,然后通过validate方法确认是否进行写模式,如果没有进入,就成功避免了开销;如果进入,则尝试获取读锁。

如何让Java线程彼此同步?了解过那些同步器?请分别介绍下。
JUC中的同步器三个主要成员:CountDownLatch、CyclicBarrier和Semaphore,通过它们可以方便的实现很多线程之间的协助功能。CountDownLatch叫倒计数,允许一个或者多个线程等待某些操作完成。
- 跑步比赛,裁判需要等到所有运动员都跑到终点才能计算成绩。
- 模拟并发,需要启动100个线程同时访问某个地址,希望他们能并发执行而不是一个一个执行
用法:CountDownLatch 构造方法指明计数数量,被等待线程调用countDown 将计数器减1,等待线程使用await进行线程等待。

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

Semaphore ,Java版本的信号量实现,用于控制同时访问的线程个数,来达到限制通用资源访问的目的,其原理通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可。

如果、Semaphore 的数值被初始化为1,那么一个线程就可以通过acquire进入互斥状态,本质上和互斥锁是非常相似的。但是区别也非常明显,比如互斥锁是持有者的,而对于Semaphore 这种计数器结构,虽然有类似功能,但其实不存在真正意义上的持有者,除非进行扩展包装。
CyclicBarrier 和CountDownLatch 看起来很相似,对比一下?
首先它们的行为有相似度,主要区别如下
- CountDownLatch 是不可以重置的,所以无法重用,CyclicBarrier没有这种限制,可以重用
- CountDownLatch 的基本操作组合是countDown/await,调用await的线程阻塞等待countDown足够的次数,不管是一个线程还是多个线程countDown,只要次数足够就可以。CyclicBarrier的基本操作组合是await,当所有的伙伴都调用了await(),才会执行任务,并且自动重置。
- CountDownLatch目的是让一个线程等待其他N个线程达到某个时间后自己再去做某个事情(通过CyclicBarrier 第二个构造方法 public CyclicBarrier(int parties,Runnable barrierAction),在新线程里做事可以达到同样的效果),而CyclicBarrier 的目的是让N多个线程相互等待知道所有的线程都打到某个状态,然后这N个线程再去执行后续的事情。(通过CountdownLatch在某些场合也能完成类似的效果)
相关文章:
深入理解java并发编程之aqs框架
跟synchronized 相比较,可重入锁ReentrankLock其实原理有什么不同? 所得基本原理是为了达到一个目的;就是让所有线程都能看到某种标记。synchronized通过在对象头中设置标记实现了这一目的,是一种JVM原生的锁实现方式。而Reentran…...
ubuntu配置tftp、nfs
tftp配置 tftp是简单文件传输协议,基于udp实现传输。这里的简单文件,指的是不复杂、开销不大的文件。 先在ubuntu中安装tftp,输入命令:sudo apt-get install tftp-hpa tftpd-hpa。 接着配置tftp。 输入命令:sudo v…...
Sklearn的datasets模块与自带数据集介绍
datasets 模块 用 dir() 函数查看 datasets 模块的所有属性和函数 import sklearn.datasets as datasets# 列出 sklearn.datasets 模块中的所有属性和函数 print(dir(datasets)) datasets 模块下的数据集有三种类型: (1)load系列的经典数…...
css 个人喜欢的样式 速查笔记
起因, 目的: 记录自己喜欢的, 觉得比较好看的 css. 下次用的时候,直接复制,很方便。 1. 个人 html 模板, 导入常用的 link 设置英语字体: Noto导入默认的 css使用网络 icon 图标导入 Bootstrap css 框架 html <…...
C/C++ let __DATE__ format to “YYYY-MM-DD“
C/C let DATE format to “YYYY-MM-DD” code: #include <iostream> #include <string>class compileDate {// 静态函数,用来格式化并返回编译日期 static std::string formatCompileDate() {// 编译时的日期,格式为 "MMM…...
git如何灵活切换本地账号对应远程github的两个账号
git如何灵活切换本地账号对应远程github的两个账号 问题: 有时候我们会同时维护两个github的账号里面的仓库内容,这时候本地git需要频繁的切换ssh,以方便灵活的与两个账号的仓库可以通信。这篇日记将阐述我是怎么解决这个问题的。1. 第一个账…...
Python中实现函数的递归调用
在Python中,函数的递归调用是一种非常强大且常用的编程技巧,它允许函数在其执行过程中调用自身。递归调用在解决许多问题时都显得尤为方便,比如遍历树形结构、计算阶乘、实现快速排序等。然而,递归也需要谨慎使用,因为…...
Multisim使用手册
目录 原件库: 基础元件库: 最右侧的分析仪们: 示波器: 交流分析: 操作: dB 一、幅频特性曲线 二、相频特性曲线 下载资源(有汉化):Multisim 14.0电路设计与仿真…...
线程的六种状态
优质博文:IT-BLOG-CN 线程的状态在Thread.State这个枚举类型中定义:共有6种状态,可以调用线程Thread种的getState()方法获取当前线程状态。 public enum State { /** * 新建状态(New): * 当用new操作符创建一个线程时&#…...
全球热门剪辑软件大搜罗
如果你要为你的视频进行配音那肯定离不开音频剪辑软件,现在有不少音频剪辑软件免费版本就可以实现我们并不复杂的音频剪辑操作。这次我就给你分享几款能提高剪辑效率的音频剪辑工具。 1.福晰音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ …...
swagger-bootstrap-ui页面空白,也没报错
回想起来,代码层面没有进行什么大的调整,增加了配置文件,application.yml中的 spring:profiles:active: sms # dev --> smsname: sms-server swagger配置未调整导致空白 修改profile 问题解决...
15.2 JDBC数据库编程2
15.2.1 数据库访问步骤 使用JDBC API连接和访问数据库,一般分为以下5个步骤: (1) 加载驱动程序 (2) 建立连接对象 (3) 创建语句对象 (4) 获得SQL语句的执行结果 (5) 关闭建立的对象,释放资源 下面将详细描述这些步骤 15.2.2 加载驱动程序 要使…...
Spark数据介绍
从趋势上看,DataFrame 和 Dataset 更加流行。 示例场景 数据仓库和 BI 工具集成: 如果你需要处理存储在数据仓库中的结构化数据,并且希望与 BI 工具集成,那么 DataFrame 和 Dataset 是首选。 机器学习流水线: 在构建机…...
【0基础】制作HTML网页小游戏——贪吃蛇(附详细解析)
我在昨天的文章(贪吃蛇HTML源码)里面分享了网页版贪吃蛇小游戏的源码,今天就来给大家详细讲解一下每部分代码是如何运作的,以及以后要如何美化贪吃蛇的UI界面,在哪里修改等。 目录 一、代码运作 1、HTML结构: 2、C…...
Vscode python无法转到函数定义
今天上午换了电脑,使用Vscode发现找不到对应的函数定义了。 使用了网上的全部教程。一点用没有。重启电脑,重启Vscode也没有作用。最后通过重装vscode,解决问题。(也不知道Vscode什么毛病) 重点语句: 去官网…...
Python中的上下文管理器(with语句)及其作用
Python中的上下文管理器(Context Manager)是一种通过with语句来管理资源(如文件、网络连接、线程锁等)的机制。with语句旨在简化常见的资源管理任务,如资源的获取、使用后的清理等。使用上下文管理器可以确保资源在使用…...
CTK框架(八):服务追踪
目录 1.简介 2.实现方式 3.具体实现 3.1.新建插件PluginA 3.2.新建插件PluginB 4.服务追踪的优势 5.应用场景 6.总结 1.简介 CTK服务追踪是一种机制,用于在CTK插件框架中追踪和管理插件提供的服务。当一个插件注册了一个服务到服务注册中心后࿰…...
[针对于个人用户] 显卡与计算卡性能对比表
笔者使用 Quadro M4000 显卡用于 LLM 相关任务,但奈何该卡发布的年代过于久远,以至于 LLM 相关任务只能使用例如:Phi3 mini、Qwen 2 2B、GLM 4 8B 以及 Gemini v2 2B等小参数模型,且速度不堪理想,也经常因为显卡过热降…...
2024年智能录屏解决方案全攻略,从桌面到云端
如果你有过录屏经验那你一定遇到过被限制录制时长或者录制的画面比较模糊之类的情况。这次我我推荐几款免费录屏软件,让我们可以更自由的录制屏幕画面。 1.福晰REC大师 链接:www.foxitsoftware.cn/REC/ 这款软件便捷好操作,而且符合我这次…...
CentOS7.9下snmp v3 inform搭建监控端
1.基础环境配置 为了防止防火墙及selinux等的影响,需关闭防火墙及selinux等,具体参考: Linux常规基础配置_linux基础配置-CSDN博客 2.安装snmp yum源配置,具体参考: Linux常规基础配置_linux基础配置-CSDN博客 snmp安装命令: yum install -y net-snmp net-snmp-ut…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
