当前位置:网站首页>AQS-AbstractQueuedSynchronizer
AQS-AbstractQueuedSynchronizer
2022-08-02 11:27:00 【是菜菜的小严惜哎】
目录
AQS简介
上一篇整理,知道了synchronized的使用,以及synchronized的原理,还有管程
管程就是通过加锁来保证并发安全,用的比较多的,就是MESA
MESA内部存在同步等待队列和许多的条件等待队列,获取锁失败的线程会进入同步等待队列
而synchronized是JVM层面对管程的实现,是基于对象的,通过ObjectMonitor来实现,获取锁失败的线程,会进入到cxq队列,这就是同步等待队列,而wait,notify,notifyAll,就是条件等待队列
但是synchronized也有缺点:自动加锁解锁,不支持手动解锁;实现比较重
这是synchronized的缺点,并且没办法改变
那,在保证性能的前提下,Java层面该怎么实现管程,于是开发大佬就搞出来了接下来的东西
并发这块,用的很多的锁,除了synchronized,很多人都会想到ReentrantLock,而ReentrantLock也是有基础的,那就是基于AQS
AQS是什么,就是AbstractQueuedSynchronizer的简写
java.util.concurrent包中大多数的同步器实现,如Lock、Latch、Barrier,都是围绕着一个共同的基本行为,比如等待队列、条件队列、独占获取、共享资源等等,这些行为的抽象就是基于AQS实现的,AQS是一个抽象同步框架,可以用来实现一个依赖状态的同步器
AQS具备的特性
AQS具备如下特性:
- 阻塞等待队列
- 共享/独占
- 公平/非公平
- 可重入
- 允许中断
AQS内部维护属性
volatile int state
state表示资源的可用状态,访问state,有三种方式
getState(), setState(), compareAndSetState()
AQS资源共享方式
AQS定义了两种资源共享方式
- Exclusive-独占,只有一个线程能执行,比如,ReentrantLock
- Share-共享,多个线程可以同时执行,比如,Semaphore、CountDownLatch
AQS队列
AQS有两种队列,分别是同步等待队列和条件等待队列
同步等待队列主要用于维护获取互斥锁失败时入对的线程
条件等待队列主要用于,线程调用await()方法时释放锁,进入条件队列,等调用了signal()方法唤醒的时候,会把条件队列中的线程节点移动到同步队列,等待重新获取锁
AQS队列中节点状态
AQS定义了五种线程在队列中的节点状态
- 值为0,初始化状态,表示当前节点在sync队列中,等待获取锁
- CANCELLED,值为1,表示当前线程被取消
- SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark
- CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
- PROPAGATE,值为-3,表示当前场场景下后续的acquireshared能够得以执行
AQS实现的线程等待队列的维护方法
不同的自定义同步器竞争共享资源的方式不同,自定义同步器在实现时只需要实现共享资源state的获取与释放就可以,至于具体的线程等待队列的维护,比如资源获取失败入队,唤醒出队等等,AQS已经在最顶层实现好了,自定义同步器实现时主要实现以下几种方法
- isHeldExclusively():该线程是否正在独占资源,只有用到了condition才需要去实现它
- tryAcquire(int):独占方式,尝试获取资源,成功就返回true,失败就返回false
- tryRelease(int):独占方式,尝试释放资源,成功就返回true,失败就返回false
- tryAcquireShared(int):共享方式,尝试获取资源,负数表示失败;0表示成功,但是i没有剩余资源可用;正书表示成功,并且有剩余资源
- tryReleaseShared(int):共享方式,尝试释放资源,如果释放后允许唤醒后续等待节点返回true,否则返回false
同步等待队列
AQS中的同步等待队列,也称为CLH队列,是一种基于双向链表结构的队列,是一种先入先出的等待队列,AQS依赖于CLH队列来完成对同步状态的管理,至于为什么叫CLH队列,那是因为,CLH队列是Craig、Landin、Hagersten三人发明的
如果当前线程获取同步状态失败,AQS会把当前线程已经等待状态等信息构造成一个节点,并将其加入到CLH队列,同时会阻塞当前线程
当同步状态被释放时,会唤醒首节点(公平锁),使其在此尝试获取同步状态
通过signal或者signalAll可以将条件队列中的节点转移到同步队列
条件等待队列
AQS中条件等待队列是用单向列表保存的,用nextWaiter来拼接
调用await()方法阻塞线程
当前线程存在于同步队列的头节点,调用await()方法进行阻塞,从而就由同步队列转换为了条件队列
Condition
可以将Condition通俗的理解为条件队列
调用Condition#await方法会释放当前持有的锁,然后阻塞当前线程,同时向Condition队列尾部添加一个节点,所以调用Condition#await方法的时候必须持有锁
调用Condition#signal方法会将Condition队列的首节点移动到阻塞队列尾部,然后唤醒因调用Condition#await方法而阻塞的线程(唤醒之后这个线程就可以去竞争锁了),所以调用Condition#signal方法的时候必须持有锁,持有锁的线程唤醒被因调用Condition#await方法而阻塞的线程
边栏推荐
- 365天挑战LeetCode1000题——Day 047 设计循环队列 循环队列
- Problem solving in the process of using mosquitto
- npm run serve启动报错npm ERR Missing script “serve“
- MySql模糊查询大全
- Com多进程通信实现
- org.apache.ibatis.binding.BindingException Invalidbound statement (not found)的解决方案和造成原因分析(超详细)
- 您应该知道的 Google Sheets 使用技巧
- SQL 数据更新
- 面积曲线AUC(area under curve)
- Nanny Level Tutorial: Write Your Own Mobile Apps and Mini Programs (Part 2)
猜你喜欢
面积曲线AUC(area under curve)
Com多进程通信实现
C#/VB.NET to add more lines more columns image watermark into the Word document
【Acunetix-Forgot your password】
Getting Started with Three.JS Programmatic Modeling
365天挑战LeetCode1000题——Day 047 设计循环队列 循环队列
sva assertion data
FinClip | 来了, 2022 年 7 月更新大盘点
LeetCode每日一练 —— 20. 有效的括号
使用kubesphere图形界面创建一个devops的CI/CD流程
随机推荐
MP的几种查询方式
idea常用插件
jvmxmx和xms参数分析(设定优化校准)
放苹果(暑假每日一题 13)
21 Days Learning Challenge - Day 1 Punch (Screen Density)
MySql模糊查询大全
AlphaFold又放大招,剑指整个生物界!
SQL(面试实战07)
使用mosquitto过程中的问题解决
pyqt5连接MYSQL数据库问题
有奖征集|TaoCloud&宝德联合举办全闪POC!
ansible module --yum module
[kali-information collection] (1.9) Metasploit + search engine tool Shodan
jacoco的学习以及理解
MySQL百万数据优化总结 一
【Acunetix-忘记密码】
多线程之生产者与消费者
图形处理单元(GPU)的演进
Outsourced Student Management System Architecture Documentation
ansible模块--yum模块