AQS框架图-Java锁机制-同步器框架

AbstractQueuedSynchronizer是整个java.util.concurrent包的核心。在JDK1.5时引入,该包中的大多数同步器都是基于AQS来构建的。

AQS框架提供了一套通用的机制来管理同步状态(synchronization state)、阻塞/唤醒线程、管理等待队列。

我们所熟知的ReentrantLock、CountDownLatch、CyclicBarrier等同步器,其实都是通过内部类实现了AQS框架暴露的API,以此实现各类同步器功能。这些同步器的主要区别其实就是对同步状态(synchronization state)的定义不同。

其实AbstractQueuedSynchronizer主要就是维护了一个state属性、一个FIFO队列和线程的阻塞与解除阻塞操作。state表示同步状态,它的类型为32位整型,对state的更新必须要保证原子性。这里的队列是一个双向链表,每个节点里面都有一个prev和next,它们分别是前一个节点和后一个节点的引用。需要注意的是此双向链表除了链头其他每个节点内部都包含一个线程,而链头可以理解为一个空节点。

锁的含义

synchronized可以用于获取实例的锁。Java的每个实例都持有一个“锁”,但同一个锁不可以由两个以上的线程同时获取。这种结构是Java编程规范规定的。这是Java语言从一开始就提供的所谓的物理锁

而AQS提供的锁与使用synchronized获取的锁是不一样的。这并不是Java编程规范规定的结构。这是所谓的逻辑锁

1、AQS(AbstractQueuedSynchronizer) 原理图

2、AQS框架

扫描二维码关注公众号,回复: 9826364 查看本文章

3、Node结构

4、首个获取锁的线程,AQS中的等待队列还是空。

5、当AQS队列为空的时候,先创建一个dummy头结点

6、进入下一次循环,插入队尾结点。(因为并发插入的情况存在,所以该方法设计成了自旋操作)

7、插入完ThreadB后,队列的初始状态如下:

8、虽然ThreadB是队首结点,但是它拿不到锁(被ThreadA占有着),所以ThreadB会阻塞,但在阻塞前需要设置下前驱的状态,以便将来可以唤醒我:

9、添加ThreadC的过程和ThreadB完全一样,同样拿不到锁,然后加入到等待队列队尾

10、

11、同步队列是AQS很重要的组成部分,它是一个双端队列,遵循FIFO原则,主要作用是用来存放在锁上阻塞的线程,当一个线程尝试获取锁时,如果已经被占用,那么当前线程就会被构造成一个Node节点假如到同步队列的尾部

12、队列的头节点是成功获取锁的节点,当头节点线程是否锁时,会唤醒后面的节点并释放当前头节点的引用。 

13、独占锁的获取和释放流程

14、自旋锁

15、CLH

16、

发布了32 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/okxuewei/article/details/85156270