AQS底层原理及源码分析详解

更新时间:2023-06-14 02:56:34 阅读: 评论:0

AQS底层原理及源码分析详解
⼀. AQS是什么
队列同步器AbstractQueuedSynchronizer(简称为AQS),是⽤来构建锁或者其他同步组件的基础框架,通过内置的FIFO(先来先服务)队列来完成资源获取线程的排队⼯作。AQS是实现锁的关键,简单理解两者的关系就是:锁是⾯向使⽤者的;AQS⾯向的是锁的实现者,简化了锁的实现⽅式,屏蔽了同步状态管理,线程排队,等待唤醒底层操作的细节,对外放出模板⽅法供⼦类实现。
⼆. AQS底层原理
AQS内部⽤⼀个volatile修饰的int类型的成员变量state来控制同步状态。
state = 0:表⽰没有线程正在独占共享资源的锁。
state = 1:表⽰有线程正在共享资源的锁。星巴克英语
1. AQS类图(红⾊线是内部类)
AbstractOwnableSynchronizer:抽象类,定义了存储独占当前线程的属性和设置,获取当前线程的⽅法。
AbstractQueuenSynchronize:抽象类,AQS框架核⼼类,内部以虚拟队列的⽅式管理线程的锁获取与锁释放,其中获取锁(tryAcquire⽅法)和释放锁(tryRelea⽅法)并没有提供默认的实现,需要
⼦类重写⽅法的具体逻辑,⽬的是为了使开发⼈可以⾃定义获取锁和释放锁的⽅式。
Node:AbstractQueuenSynchronize的内部类,⽤于构建虚拟队列(双向链表),为每个进⼊同步队列的线程封装成Node对象加⼊队列,管理需要获取锁的线程。
Sync:抽象类,是ReentrantLock的内部类,继承了AbstractQueuenSynchronize,实现了tryRelea⽅法,并提供抽象⽅法lock,供⼦类实现
NonfairSync:Reentrantlock的内部类,继承Sync,⾮公平锁的实现类
FairSync:Reentrantlock的内部类,继承Sync,公平锁的实现类
Reentrantlock:实现了Lock接⼝,创建时默认为⾮公平锁。
2. AQS类详解
AQS虽说是⼀个抽象类,但是其内部没有⼀个⽅法是抽象⽅法,因为AQS只是基础的组件,作者并不希望使⽤者对其直接进⾏操作,更倾向于其作为基础组件,为其实现类提供基础的帮助。
AQS采⽤的是模板⽅法模式,其内部除了提供并发的操作核⼼⽅法以及同步队列的操作之外,还提供了⼀些模板⽅法让⼦类⾃⼰实现,如加锁解锁。
AQS作为基础的组件,封装的都是核⼼的并发操作,实际上还分为两种模式,共享模式和独占模式,如
Reentrantlock,ReentrantReadWriteLock(写锁部分)都是独占锁,ReentrantReadWriteLock(读锁部分)就是共享锁。
这两种模式的解锁和加锁逻辑都不⼀样,但是AQS只关注内部的公共⽅法的实现,不关⼼外部的具体实现,所以提供了模板⽅法给⼦类。查干湖旅游
要实现独占模式,则需要实现tryAcquire(加锁)和tryRelea(解锁),⽽实现共享模式则需要实现tryAcquireShared(加锁)和tryReleaShared(解锁),⽆论是共享模式还是独占模式,其底层实现都是同⼀个AQS,只是加锁和解锁逻辑不⼀样,所以,根据⾃⼰的需求⾃定义锁也就变得简单。
看看AQS提供的5个模板⽅法:
AQS的作⽤基本有了概念,那么AQS到底怎么⼯作的呢?
先来看看它的内部类:Node
有的属性基本看注释就能看懂啥意思,让我们看看waitStatus的5个常数的含义
CANCELLED:值为1,在同步队列中等待超时或被中断,需要从同步队列中取消该Node的节点,其节点的waitStatus为
CANCELLED,即结束状态,进⼊该状态后的节点将不会再变化。
SIGNAL:值为-1,被标识为该等待唤醒状态的后序结点,当其前序节点的线程释放了同步锁被取消,将会通知该节点的后序节点的线程执⾏。就是处于唤醒状态,只要前序节点释放锁,就会通知标识为SIGNAL状态的后序节点的线程执⾏。
CONDITION:值为-2,与Condition相关,该标识的节点处于等待队列中(后⾯会说)节点的线程等待在Condition上,当其他线程调⽤了Condition的signal()⽅法后,CONDITION状态的节点将从等待队列转移到同步队列中,等待获取同步锁。
植树节在几月几日
PROPAGATE:值为-3,与共享模式相关,在共享模式中,该状态标识节点的线程处于可运⾏状态。
0状态:值为0,代表初始状态
3. Condition(等待队列)
任何的⼀个对象,都有⼀组监视器⽅法(定义在Object上),主要包括wait,wait(long),notify,notifyAll⽅法,主要与synchronized同步关键字使⽤,可以实现等待通知的作⽤。同理,ConditionObject是AQS的内部类,因为Condition的操作需要先获取相关联的锁,所以在同步器的内部也合理。
等待队列是什么?
卢东生
等待队列是⼀个FIFO的队列,每个节点都包含⼀个线程的引⽤,该线程就是在Condition对象中等待的线程,如果线程调⽤了await⽅法,线程将会加⼊等待线程,释放锁,并进⼊等待状态。节点都是AQS的静态内部类Node。
4. AQS⼯作详解
下图就是AQS底层模型图:
当线程调⽤await⽅法(线程先进⼊队列,后释放锁):
线程调⽤signal⽅法(移动到同步队列尾部,唤醒线程):
5. 源码分析
先看AQS底层分装的核⼼⽅法唯唯连声的意思
为了⽅便理解,这边加⼊Reentrantlock⼦类实现代码
final void lock(){
//cas操作设置state的值,如果state为0,则说明当前共享资源没有线程占⽤,设置为1,成功后设置独占线程为当前线程。
if(compareAndSetState(0,1))
tExclusiveOwnerThread(Thread.currentThread());
el
//如果state不为0,则说明有线程独占了,进⼊AQS核⼼⽅法,上图可见,随后进⼊tryAcquire⽅法
acquire(1);
}
沙漠探险//这是⼦类具体实现⽅法实现锁的逻辑,进⼊nonfairTryAcquire⽅法
protected final boolean tryAcquire(int acquires){
return nonfairTryAcquire(acquires);
}
//acquires = 1
final boolean nonfairTryAcquire(int acquires){
批量转pdf//获取当前线程
final Thread current = Thread.currentThread();
//获取state状态
int c =getState();
//如果状态为0,跟之前⼀样,则进⼊cas设置,并将独占线程设置为⾃⼰,返回true
if(c ==0){
if(compareAndSetState(0, acquires)){
tExclusiveOwnerThread(current);
白蛇传传说
return true;
}
}
//如果state不为0,且当前线程为独占线程,进⾏+1,也就是重⼊锁的实现。
el if(current ==getExclusiveOwnerThread()){
int nextc = c + acquires;
if(nextc <0)// overflow
throw new Error("Maximum lock count exceeded");
tState(nextc);
return true;
}
/
/如果都不满⾜,表⽰既有独占线程,当前线程⼜不是独占线程,则要进⼊同步队列,等待锁的释放。这⼀步完进⼊AQS核⼼代码也就是第⼀个图return fal;
}

本文发布于:2023-06-14 02:56:34,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/949382.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   队列   实现   节点   等待   模式   状态
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图