当前位置:网站首页>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方法而阻塞的线程
边栏推荐
- 翁恺C语言程序设计网课笔记合集
- Shell编程之条件语句
- org.apache.ibatis.binding.BindingException Invalidbound statement (not found)的解决方案和造成原因分析(超详细)
- jvmxmx和xms参数分析(设定优化校准)
- 10份重磅报告 — 展望中国数字经济未来
- 使用mosquitto过程中的问题解决
- leetcode: 200. 岛屿数量
- Deep Learning 100 Examples - Convolutional Neural Network (CNN) for mnist handwritten digit recognition
- ECCV22|PromptDet:无需手动标注,迈向开放词汇的目标检测
- Coroutines and Lifecycle in Kotlin
猜你喜欢
随机推荐
Create an application operation process using the kubesphere GUI
微信小程序---组件开发与使用
注意力机制
org.apache.ibatis.binding.BindingException Invalidbound statement (not found)的解决方案和造成原因分析(超详细)
MySQL百万数据优化总结 一
当POC遇见RPA:RPA项目顺利实施的关键
Mysql事务隔离级别与MVCC(多版本并发控制)
初探zend引擎
21 Days Learning Challenge - Day 1 Punch (Screen Density)
Several reasons why applet plugins benefit developers
循环语句综合练习
Three.JS程序化建模入门
ES2020-23简单易懂又实用的精选特性讲解 日常开发必备干货!
8大软件供应链攻击事件概述
打破千篇一律,DIY属于自己独一无二的商城
使用mosquitto过程中的问题解决
Oracle查询提示 ORA-00933 SQL command not properly ended 原因排查
MP的几种查询方式
外包学生管理系统架构文档
pyqt5连接MYSQL数据库问题