1:AQS是什么
AQS:全称AbstractQueuedSynchronizer(抽象类的队列式同步器). 是JUC包下的一个抽象类. aqs因为是抽象类,本身并不提供同步的接口,但JUC下的其他同步组件都是基于aqs来进行实现同步的,比如(:ReentrantLock、CountDownLatch、Semaphore)这些都是继承自aqs.所以aqs在并发编程中是至关重要的知识点.
2:实现AQS的类
AQS支持线程抢占两种锁——独占锁和共享锁:
- 实现独占锁的类:ReentrantLock、ReentrantReadWriteLock.WriteLock
- 实现共享锁的类:ReentrantReadWriteLock.ReadLock、CountDownLatch、CyclicBarrier、Semaphore
独占锁Exclusive:同一个时刻只能被一个线程占有,它又可分为:
公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的
共享锁Share:同一时间点可以被多个线程同时占有.
3:AQS的实现原理
FIFO线程等待队列
AQS的实现依赖内部的同步队列,也就是FIFO的双向队列,如果当前线程竞争锁失败,那么AQS会把当前线程以及等待状态信息构造成一个Node(如下图)加入到同步队列中,同时再阻塞该线程。当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。
队列内部维护的是一个FIFO的双向链表,这种结构的特点是每个数据结构都有两个指针,分别指向直接的后继节点和直接前驱节点,所以双向链表可以从任意一个节点开始很方便的访问前驱和后继。每个Node其实都是由线程封装的,当线程争抢锁失败后会封装成Node加入到AQS队列中去。
volatile int state(共享资源)
state用来表示当前的同步状态,根据当前state的值,来判断当前释放处于锁定状态,或者是其他状态。当state=1时代表当前对象锁已经被占用,其他线程来加锁时则会失败,失败的线程被放入一个FIFO的等待队列中,然后会被UNSAFE.park()操作挂起,等待已经获得锁的线程释放锁才能被唤醒。我们继承AQS时,根据自己的需求,实现一些方法,其中就是通过修改state的值来维持同步状态。主要方法如下:
//获取当前同步状态state的值
int getState()
//设置当前同步状态state的值
void setState(int newState)
//使用CAS设置当前同步状态的值,方法能够保证设置同步状态时的原子性;
//参数expect为state的预期旧值,而update是需要修改的新值,若设置成功,方法返回true,否则false
boolean compareAndSetState(int expect, int update)
4:AQS相关的关系脑图
脑图引用的文章: AQS简介(附脑图)_Linias的博客-优快云博客