图解AQS源码分析(上)

简介: AbstractQueuedSynchronizer抽象的队列式同步器(抽象类)。提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLock、CountDownLatch等。

1 简介


AbstractQueuedSynchronizer抽象的队列式同步器(抽象类)。提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLock、CountDownLatch等。


其中比较重要的概念有:


state共享资源

FIFO

CAS

park  unpark


2 AQS线程队列


Node是整个队列中最核心的部分,包含CANCELLED、SIGNAL、CONDITION、PROPAGATE四种状态、指向前后节点的指针、thread是节点存储的值。


ReentrantLock中的公平锁与非公平锁都继承了这个抽象类。


20200916104953811.png


ReentrantLock包含公平锁和非公平锁,每种锁里面还包含了抽象的锁Sync,抽象锁执行AQS。


如果当前是线程1拥有锁的话,线程2,3,4会调用park操作来被挂起加入队列中。


当拥有锁的Thread1执行完毕后会调用unpark方法,head指向下一个节点。由于ReentrantLock是一个可重入锁,重入次数被AQS.state记录,每重入一次值 + 1,退出一次 - 1。


3 ReentrantLock实例构建


ReentrantLock默认构造函数创建的是非公平锁,如果想要公平锁的话需要在构造方法中传入true。


20200916105033289.png20200916105033289.png

20200916105033289.png


4 多线程抢锁图示(非公平锁)


线程抢到锁的过程使用CAS实现。

初始时等待队列只有一个Head节点,其中存储的Thread是null,用来占位,线程B,C在队列中使用双向链表的方式与Head相连,调用park挂起。


20200916105236422.png


上图的分步过程见下文。


4.1 A线程加锁


A线程抢锁时通过CAS操作将state改为1,并将AQS的exclusiveOwnerThread属性设为A,表示当前锁的拥有者。


2020091610532027.png


4.2 B线程加锁


此时B线程要进行抢锁,发现state已经是1了,所以CAS操作失败,进入到队列中,waitStatus设置为0

第一次new Node的时候,即创建head,thread设置为了null,waitStatus设置为SIGNAL


20200916105236422.png


4.3 C线程加锁


接着C线程抢锁时,操作同B,会将B的waitStatus设置为SIGNAL,自己的是初始化是的值0


20200916105412111.png


新插入的节点waitStatus值都设为0原因是用来标记队列中最后一个节点,此时不必再进行对后续节点的unpark操作,等待队列中没有节点时会有一个null的节点用作占位,这两个操作都是防止等待队列中没有等待的线程时而变为空。




4.4 A线程解锁


A线程进行解锁操作之后,B线程可以抢到锁,流程如下:


A线程解锁操作:


state设为0

exclusiveOwnerThread设为null表示锁被释放

head节点向后移动一位进行unpark操作唤醒线程B

之前的head节点要被释放


image.png


4.5 B线程解锁


2020091610555516.png


4.6 C线程解锁


20200916105618596.png

相关文章
|
4月前
|
存储 算法 安全
剑指JUC原理-5.synchronized底层原理(上)
剑指JUC原理-5.synchronized底层原理
36 0
|
7月前
AQS源码解读之一
AQS源码解读之一
23 0
|
8月前
AQS原理
AQS原理
36 0
AQS原理
|
9月前
|
Java 开发者
每天一道面试题之-AQS
每天一道面试题之-AQS
84 0
|
10月前
|
Java 程序员 API
AQS 原理解读
AQS 原理解读
|
机器学习/深度学习 Java 调度
浅谈AQS原理
经典八股文之AQS原理
173 0
把 AQS 源码扒个「体无完肤」​!
AbstractQueuedSynchronizer是 Doug Lea 大师创作的用来构建锁或者其他同步组件的基础框架类。J.U.C 中许多锁和并发工具类的核心实现都依赖于 AQS,如:ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch 等。
88 0
|
安全 Java
Java并发之AQS源码分析(二)
我在 Java并发之AQS源码分析(一)这篇文章中,从源码的角度深度剖析了 AQS 独占锁模式下的获取锁与释放锁的逻辑,如果你把这部分搞明白了,再看共享锁的实现原理,思路就会清晰很多。下面我们继续从源码中窥探共享锁的实现原理。
126 0
Java并发之AQS源码分析(二)
|
存储 Java
Java并发之AQS源码分析(一)
AQS 全称是 AbstractQueuedSynchronizer,顾名思义,是一个用来构建锁和同步器的框架,它底层用了 CAS 技术来保证操作的原子性,同时利用 FIFO 队列实现线程间的锁竞争,将基础的同步相关抽象细节放在 AQS,这也是 ReentrantLock、CountDownLatch 等同步工具实现同步的底层实现机制。它能够成为实现大部分同步需求的基础,也是 J.U.C 并发包同步的核心基础组件。
105 0
Java并发之AQS源码分析(一)
图解AQS源码分析(下)
AbstractQueuedSynchronizer抽象的队列式同步器(抽象类)。提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLock、CountDownLatch等。
图解AQS源码分析(下)