AQS简单介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AQS简单介绍相关的知识,希望对你有一定的参考价值。

参考技术A 通过其内部结构大致可以了解到

1、AQS其实是一个双向链表,有head、tail节点分别代表首尾节点;每个节点的元素的类型是Node;

2、在AQS中维护了一个int类型的state属性,这个属性在不同的子类中存在不同的含义;例如在Semaphore中表示的就是信号量;在ReentrantLock中表示的是当前线程获取锁的可重入次数;

3、在Node节点中的thread表示的是进入到AQS中的线程;其中SHARED表示的是该线程是在获取共享资源被阻塞后台放入到阻塞队列中的;EXCLUSIVE表示是在获取独占资源被阻塞后放入到阻塞队列中的;在Node中的waitStatus表示的是对应线程的状态,其中CANCELLED(1:线程已经被取消)、SIGNAL(-1:表示线程需要被唤醒)、CONDITION(-2:线程在条件队列里面等待)、PROPAGATE(-3:释放共享资源时需要通知其他线程)表示对应的

大致了解之后,来看一下AQS中几个相当重要的方法;

1、该方法获取独占资源,先调用tryAcquire方法尝试获取独占资源;该方法的实现有子类定义;

2、在独占的资源没有获取到的时候,向队列中添加一个EXCLUSIVE类型的的Node节点到AQS阻塞队列的尾部;

3、然后调用LockSupport.park(this)挂起;

接下来一个简单了解一下每个方法的内部执行逻辑

(1)为当前线程构建一个新的node节点;

(2)获取AQS队列中的尾节点;

(3)判断尾节点是否不为null;

(4)当前AQS队列中的tail节点为null,那么这个时候可以认为AQS队列为null,然后通过enq(fianl Node node)方法进行元素新增;

接下来简单分析一下enq(fianl Node node)方法;

此方法根据boolean addWaiter(Node mode)方法的执行情况进行分析;

1、当AQS中的tail节点为null时,进入此方法,也就是第一次循环

2、(2.2)中将head节点的值赋值给了tail节点之后,第一次循环结束,进行第二次循环,这次循环很明显tail != null了

然后进入(3)

执行相关的大致流程图:

然后再看acquireQueued(final Node node, int arg)方法

接着addWaiter方法来分析一下acquireQueued方法;

1、 获取当前节点的prev节点

2、 如果prev节点为head节点,那么它就有资格去争抢锁,调用tryAcquire抢占锁

3、 抢占锁成功以后,把获得锁的节点设置为head,并且移除原来的初始化head节点

4、如果获得锁失败,则根据waitStatus决定是否需要挂起线程

5、 最后,通过cancelAcquire取消获得锁的操作

1、该方法会先调用boolean tryRelease(int arg)方法尝试释放资源(具体实现由子类定义)

2、在释放资源成功后,判断AQS队列中是否存在被阻塞的线程

3、存在被阻塞的线程则调用void unparkSuccessor(Node node)进行唤醒;

以上是关于AQS简单介绍的主要内容,如果未能解决你的问题,请参考以下文章

AbstractQueuedSynchronizer的简单介绍

J.U.C之AQS介绍

AQS 原理以及 AQS 同步组件总结

AQS 详解

AQS

JAVA私房菜专栏之AQS