我是一个使者,不为所斩,但求已知
AbstractQueueSynchronizer,抽象的队列式同步器, 简称 AQS,一般用于支持其他框架,在多线程中常用
工作原理:
把所有请求线程构成一个CLH队列,当一个线程执行完毕lock.unlock时会激活自己后续节点,正在执行的线程不在队列中,等待执行的线程全部处于阻塞状态
比如ReentrantLock,先通过CAS尝试获取锁。如果此时已经有线程占据了锁,那就加入CLH队列 队尾并且被挂起 自旋。当锁被释放之后,排在CLH队列队首的线程会被唤醒,然后CAS再次尝试获取锁。
在这个时候,如果:
非公平锁:如果同时还有另一个线程进来尝试获取,那么有可能会让这个线程抢先获取
公平锁: 如果同时还有另一个线程进来尝试获取,当它发现自己不是在队首的话,就会排到队尾,由队首的线程获取到锁。
AQS维护一个共享资源volatile的整型变量state,通过内置的FIFO来完成获取资源线程的排队工作。(这个内置的同步队列称为**"CLH"队列**:带头节点的双向非循环链表)。该队列由一个一个的Node结点组成,每个Node结点维护一个prev引用和next引用,分别指向自己的前驱和后继结点。AQS维护两个指针,分别指向队列头部head和尾部tail。
结构如下
参考大神画好的图😂😂😂😂😂
应用
我们常用的CountDownLatch、ReentrantLock、Semaphore等类都是在内部定义了一个叫做Sync的内部类,而Sync类继承了AQS抽象类并重写了一些必要的方法,这是作为公平/非公平的设置
对于Semaphore来说,state用来表示当前可用信号的个数;
对于CountDownlatch来说,state用来表示计数器当前的值
独占锁以ReentrantLock为例,state初始值为0,表示未锁状态,当一个线程执行了lock()方法之后,会调用tryAcquire方法独占该锁并将state+1,此后其他线程尝试获取锁时便会失败,进入队列,直到刚才的线程释放锁将state值更改为0时,其他线程才有机会获取这个独占锁。当然,这个锁时可重入的,获得锁的线程可以继续state+1,不过只有state为0的时候其他线程才会唤醒。
共享锁以CountDownLatch为例,初始化线程数为n,及将state初始值设置为n,表示可以有n个线程同时获取这个共享锁,当有线程执行一countDown(),state就会CAS的方式减少1,知道所有线程执行完,state值为0的时候,会unpark主线程,然后主线程会从await状态被唤醒返回,继续执行其他指令。
一般情况自定义同步器要么是独占方法,要么是共享方式,他们也只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。需要说明的是AQS也支持同时实现独占同步和共享同步,比如ReentrantReadWriteLock。
以上都是通过其内部compareAndSetState方法设置,这个方法被引用了多少大家可以自己看一下,我先截个图
好了,今天就到这里,祝你好运!🤞🤞🤞🤞🤞
借鉴:https://www.cnblogs.com/ZoHy/p/11300095.html