AQS
AQS这个类定义了一套多线程访问共享资源的同步器框架,AQS是整个JUC包的基石,JUC包内几乎所有线程间同步的组件都依赖于AQS。AQS简单来说就是用来同步的,主要是维护了一个state变量和一个CLH同步队列。
AQS建议实现类定义为非public的内部类。因为AQS其实是一个抽象的同步器,一个同步框架,封装了通用的同步逻辑,大多数时候实现类可以看成一个适配器,比如ReentrantLock中的Sync修饰关键字为static final.
独占模式和共享模式
AQS有独占和共享两种实现方式。
独占锁和共享锁获取同步状态都是调用这个方法,aquire方法用一个布尔型变量来区分独占/共享,独占锁和共享锁的区别主要是state变量,独占锁state变量肯定是0或1,共享锁state>0;独占锁释放锁后唤醒下一个结点,共享锁唤醒所有结点。
CLH队列
CLH队列是AQS的核心组件。AQS将每个等待锁的线程封装成Node结点,并维护由这些Node组成的CLH队列(可以看成一个双向链表,每个Node都有前驱和后继指针)和一个int类型的核心变量state,用来记录当前的状态。当发生竞争的时候,AQS会将线程封装为Node并入队等待。
Node入队
- 将待入队结点的前驱设置为当前队列的tail
- 如果tail此时为null,说明队列为空,尝试CAS设置一个哨兵结点作为队列的head,如果CAS成功则将tail也指向该哨兵结点(dummy node,链表题经常用到的)
- 否则直接CAS设置tail指向待入队的结点
- 自旋重试直到步骤3成功。
acquire,获取同步状态。
获取锁流程:
- acquire(1)
- 首先调用tryAcquire(1)
- 如果不成功则将 进入acquire(Node node, int arg, boolean shared,
boolean interruptible, boolean timed, long time) 这个方法,这个方法代码很长,先考虑了当前队列为空、或者当前结点是第一个结点等等一些列情况最终才创建结点并入队。