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简单介绍的主要内容,如果未能解决你的问题,请参考以下文章