目录
前序
在学习AQS源码的时候,勾勾先介绍两个在AQS中比较重要的知识:线程interrupt方法和CAS乐观锁。
与线程中断相关的API有如下几个:
//中断方法,其他线程调用阻塞线程的intrrrupt方法,可以打断阻塞状态
public void interrupt() {... }
//判断当前线程是否中断,仅仅是对interrupt标识的判断,没有做其他事情
public boolean isInterrupted() {
return isInterrupted(false);
}
//判断当前线程是否中断,但是改方法会擦除线程的interrupt标识,
//如果当前线程被中断了,那么第一次调用返回true,且立即擦除标识,以后再调用就是false
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
CAS是乐观锁的主要实现:在更新的时候先比较当前值是否与期望的值相等,相等则更新,不相等则不更新,从而保证并发编程下共享变量的安全性。
CAS是比较简单的乐观锁,在这里只做简单介绍,勾勾在后面的文章《锁的分类》会重点讲解。
了解这两个知识点后,我们就开始AQS源码的学习吧。
AQS是JUC包的核心,勾勾的学习分为源码和实现类,源码的学习分3篇文章:独占模式(EXCLUSEIVE)、共享模式(SHARED)、条件等待(CONDITION)。
接下来就开始学习独占模式的获取操作和释放操作的源码,篇幅比较长,很多信息会写在源码的注释上,注意查收喔。
AQS介绍
AQS(AbstractQueueSynchronizer)是一个用于构建锁和同步器的框架,许多同步容器都可以通过AQS很容易并且高效的构建出来。java.util.concurrent中的许多可阻塞类,例如ReentrantLock、Semaphore、ReentrantReadWriteLock、CountDownLatch、SynchronousQueue和FutureTask等,都是基于AQS的。
在基于AQS构建的同步器中,最基本的操作包括各种形式的获取和释放操作。AQS负责管理同步容器类中的状态,它管理了一个整型的状态信息,可以通过getState,setState以及compareAndSetState等protected类型的方法来操作。这个整型状态可以代表任意状态,在不同的实现类中有不同的含义。例如ReentrantLock用它来表示所有者线程重复获取改锁的次数,Semphore用它来表示剩余的许可数量,FutureTask用它来表示任务的状态。
所以整个AQS的源码既是围绕state的获取和修改。
我们先来了解AQS的成员变量:
/**
* 等待队列的头节点,惰性初始化。 只有在执行setHead方法的时候才会被修改。
* 如果头节点存在,则需保证它的状态不是CANCELLED
*/
private transient volatile Node head;
/**
* 等待队列的尾节点, 惰性初始化. 只有向队列中添加元素的时候才会修改
*/
private transient volatile Node tail;
/**
* 同步器的状态
*/
private volatile int state;
//获取同步器的状态
protected final int getState() {
return state;
}
//设置同步器的状态
protected final void setState(int newState) {
state = newState;
}
//cas方式设置同步器的状态
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
通过对AQS的成员变量分析,除了关键的同步器状态之外,另一个关键的信息就是Node对象,那么我们就先看看Node是一个什么样的类。
双端链表Node
Node是AQS中的一个静态不可变的内部类,其结构是一个FIFO的双端链表,主要用来维护线程以及节点的等待状态。它的源码如下:
static final class Node {
/** 节点在共享状态下等待的标记 */
static final Node SHARED = new Node();
/** 节点在独占状态下等待的标记 */
static final Node EXCLUSIVE = null;
/** 因超时或者中断节点处于取消状态,取消状态的节点线程不再参与锁的竞争 */
static final int CANCELLED = 1;
/** 该节点的后继节点处于等待状态,当该节点的线程释放了锁后ÿ