当前位置:网站首页>【无标题】
【无标题】
2022-07-01 08:15:00 【今天学不学?】
AQS
AQS在java并发中的地位,相当于JVM在java中的地位,他就是抽象阻塞队列同步器,是实现同步器和锁的基石,就是base父类
抽象类:相当于base父类,可以是很多类的模板框架,组件,在抽象类的子类有很多情况
队列:用于锁的争抢,没抢到资源的到阻塞队列排队
概述:用于实现锁和其他同步器组件的公共基础部分的抽象实现,是重量级的基础框架以及JUC体系的基石,就是一个抽象FIFO队列来完成资源获取线程的阻塞队列和一个int变量的状态来表示当前资源是否被占用
Java中的大部分同步类(Lock、Semaphore、ReentrantLock等)都是基于AbstractQueuedSynchronizer(简称为AQS)实现的。AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。
在AQS中的锁类型有两种:分别是**「Exclusive(独占锁)**「和」**Share(共享锁)」**。
「独占锁」就是「每次都只有一个线程运行」,例如ReentrantLock
。
「共享锁」就是「同时可以多个线程运行」,如Semaphore、CountDownLatch、ReentrantReadWriteLock
。名称为AbstractQueueSynchronized,是阻塞式锁和相关的同步器工具的框架
概括:整体上就是一个抽象的FIFO队列来完成资源获取线程的排队任务,并通过一个int类变量表示持有锁的状态
AQS框架
AQS框架图
AQS内部体系框架
数据结构
AQS最基本的数据结构为Node节点
属性解释:
waitStatus:在队列中节点的状态
thread:当前节点的线程
prev:前驱节点
predecessor:返回前驱节点,没有的话抛出npe
nextWaiter:指向下一个处于CONDITION节点
next:后继指针
waitStatus属性值种类:
枚举 | 含义 |
---|---|
0 | 当一个Node被初始化的时候的默认值 |
CANCELLED | 为1,表示线程获取锁的请求已经取消了 |
CONDITION | 为-2,表示节点在等待队列中,节点线程等待唤醒 |
PROPAGATE | 为-3,当前线程处在SHARED情况下,该字段才会使用 |
SIGNAL | 为-1,表示线程已经准备好了,就等资源释放了 |
源码分析
从ReentrantLock中的非公平锁来进行源码分析
从lock方法进行入手
ReentrantLock实现了Lock接口,里面包含了一个sync同步器,该同步器继承了AQS类,底层lock调用了sync同步器的lock锁
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
lock.lock();
try{
//同步代码块{}
}finally {
lock.unlock();
}
}
2.sync同步器的lock方法
- 首先CAS进行判断,能否当前线程先抢到锁,如果成功,该线程直接获取资源,否则进行acquire方法尝试获取资源
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
3.acquire方法
该方法主要有三大体系
- tryAcquire:尝试获取锁,如果再次没有获取到锁,返回false,进行addWaite(Node.EXCLUSIVE)r方法的执行
- addWaiter(Node.EXCLUSIVE):如果没有获取成功,将线程加入到队列中
- 最后调用acquireQueued()方法:通过 “死循环”的方式获取同步状态
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
加入队列的时机
当执行acquire(1)时,会通过tryAcquire获取锁,在这种情况下,如果获取锁失败,就会调用addWaiter加入到等待队列中去
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();//先获取资源的状态
if (c == 0) {
//如果为0,表示该资源没有被占用,可以进行获取
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);//获取资源,返回true
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//如果获取的资源线程为当前资源线程,返回true
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
如何加入队列
获取锁失败后,执行addwaiter加入等待队列
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);//新建一个node节点
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;//取出当前尾结点
if (pred != null) {
//如果尾节点不为空 说明队列已存在阻塞线程
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);//如果尾节点为空,表示阻塞队列中还没node节点,进行入队操作
return node;
}
入队操作
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
//进行队列的初始化
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZUKGENuu-1656424435234)(C:\Users\小刘同学\Desktop\入队操作.png)]
等待队列中线程出队时机
前驱是头结点,就获取到了同步状态。
head节点表示获取锁成功的节点,当头结点在释放同步状态时,会唤醒后继节点,如果后继节点获得锁成功,会把自己设置为头结点,节点的变化过程如下
这个过程也是涉及到两个变化
- 修改head节点指向下一个获得锁的节点
- 新的获得锁的节点,将prev的指针指向null
这里有一个小的变化,就是设置head节点不需要用CAS,原因是设置head节点是由获得锁的线程来完成的,而同步锁只能由一个线程获得,所以不需要CAS保证,只需要把head节点设置为原首节点的后继节点,并且断开原head节点的next引用即可

边栏推荐
- 【入门】输入n个整数,输出其中最小的k个
- Leetcode t31: prochain arrangement
- Leetcode t40: combined sum II
- Anddroid text to speech TTS implementation
- On June 30, 2022, the record of provincial competition + national competition of Bluebridge
- 【入门】提取不重复的整数
- Provincial selection + noi Part II string
- 01 NumPy介绍
- Provincial election + noi Part VII computational geometry
- 《MATLAB 神经网络43个案例分析》:第30章 基于随机森林思想的组合分类器设计——乳腺癌诊断
猜你喜欢
Practice and Thinking on the architecture of a set of 100000 TPS im integrated message system
Intelligent water and fertilizer integrated control system
Intelligent water supply system solution
《MATLAB 神经网络43个案例分析》:第30章 基于随机森林思想的组合分类器设计——乳腺癌诊断
Field agricultural irrigation system
Embedded-c language-10-enumeration / (function) pointer (function) / multi-level pointer /malloc dynamic allocation / file operation
Access report realizes subtotal function
軟鍵盤高度報錯
Learn the knowledge you need to know about the communication protocol I2C bus
OJ input and output exercise
随机推荐
Provincial selection + noi Part II string
使用beef劫持用户浏览器
Hijacking a user's browser with beef
Keithley 2100 software 𞓜 Keithley2400 test software ns SourceMeter
Five combination boxing, solving six difficult problems on campus and escorting the construction of educational informatization
Cmake I two ways to compile source files
How to recruit Taobao anchor suitable for your own store
Luogu p3799 demon dream stick
Intelligent constant pressure irrigation system
getInputStream() has already been called for this request
Field agricultural irrigation system
Yolov5 advanced six target tracking environment construction
MATLAB小技巧(16)矩阵特征向量特征值求解一致性验证--层次分析
Aardio - Method of self constructed geticonhandle
[untitled]
基于Gazebo的无人机管道检测
Redis publish subscription
EDA开源仿真工具verilator入门6:调试实例
leetcode T31:下一排列
Book of quantitative trading - reading notes of the man who conquers the market