一、为什么需要AQS?以及AQS的作用和重要性?
AQS(AbstractQueuedSynchronizer)的重要性
AQS被用在ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch、ThreadPoolExcutor的Worker中都有运用(JDK1.8)。AQS是这些类的底层原理,JUC包里很多重要的工具类背后都离不开AQS框架。
目的是为了理解器背后的原理,学习设计思想。
我们先从宏观的角度去解读AQS,比如为什么需要AQS?AQS有什么作用。
**AQS 作用是一个用于构建锁、同步器等线程协作工具类的框架,利用AQS可以很方便的实现线程协作工具类。而且AQS被广泛应用在JUC包中。
**
很多用于线程协作的工具类就都可以很方便的被写出来
可以让更上层的开发极大的减少工作量,避免重复早轮子。
避免了上层因处理不当而导致的线程安全问题,AQS把这些都做好了。
二、AQS内部原理解析
AQS最核心的三个部分作为重点:
状态、队列(FIFO队列)、期望协作工具类去实现的获取/释放等重要方法
1、state状态
private volatile int state;
state根据具体实现类的作用不同而表示不同的含义。
例如:在信号量里面,state表示的是剩余许可证的数量
如果我们最开始把state设置为10,这就代表许可证初始一共有10个,然后当某一个线程取走一个许可证之后,这个state就会变为9,所以信号量的state相当于是一个内部计数器。
例如:在CountDownLatch工具类里面,state表示的是需要“倒数”的数量
一开始我们假设把它设置为5,当每次调用CountDown方法时,state就会减1,一致减到0的时候就代表这个门闩被放开。
例如:state在ReentrantLock中的含义
在ReentrantLock中它表示的是锁的占有情况
最开始0,表示没有任何线程占有锁,如果state变成1,则就代表这个锁已经被某一个线程所持有了。
为什么会往上加呢?
因为ReentrantLock是可重入的,同一个线程不用释放锁,可以再次拥有这把锁就叫重入,如果这个锁被同一个线程多次获取,那么state就会逐渐的往上加,state的值标识重入的次数。
state状态
state修改,因为state是会被多个线程共享的,会被并发地修改,所以去修改的state的方法都必须要保证state是线程安全的,可是state本身它仅仅被volatile修饰的,volatile本身并不足以保证线程安全。volatile的作用,当基本类型的变量进行直接赋值时,如果加了volatile就可以保证它的线程安全,这个就是setstate方法,线程安全的原因。
在AQS中有一个属性是state,它会被并发修改,它代表当前工具类的某种状态,在不同类总代表不同的含义。
2、FIFO队列
FIFO队列,即先进先出队列
这个队列最主要的作用是存储等待的线程
假设很多线程都想要同时强锁,那么大部分的线程是抢不到的,就需要有一个对了来存放、管理它们,所以AQS的一大功能就是充当线程的“排队管理器”。
这个队列是双向链表的形式,其数据结构看似简单,但是想要维护成一个线程安全的双向队列却非常复杂。
因为要考虑很多的线程并发问题。
3、获取/释放方法
获取和释放相关的重要方法,这些方法是协作工具类的逻辑的具体体现
需要每一个协作用具类自己去实现。所以在不同的工具类中,它们的实现和含义各不相同。
获取方法,获取操作通常会依赖state变量的值,根据state值不同,协作工具类也会有不同的逻辑
并且在获取的时候也会经常阻塞。
总结:
state 是一个数值,在不同的类中表示不同的含义,往往代表一种状态;
队列,该队列用来存放线程;
“获取、释放”的相关方法,需要利用AQS的工具类根据自己的逻辑去实现。
三、AQS在CountDownLatch类中的应用原理?
1、AQS用法
2、AQS在CountDownLatch的应用
3、总结
1、AQS用法,利用AQS类的主要步骤
1)新建一个自己的线程协作工具类
在内部写一个Sync类
该Sync类继承AbstractQueuedSynchronizer 即AQS。
2)想好设计的线程协作工具类的协作逻辑
在Sync类里根据是否是独占,来重写对应的方法
如果是独占,则重写tryAcquire和tryRelease等方法
如果是非独占,则重写tryAcquireShared和tryReleaseShared等方法
3)在自己的线程协作工具类中实现获取/释放的相关方法
并在里面调用AQS对应的方法
独占则调用acquire或release等方法
非独占则调用acquireShared或releaseShared 或acquireShareInterruptibly等方法。