简介
AbstractQueuedSynchronizer,简称AQS。它为java.util.conturrent包下的常用同步组件,比如ReentrantLock,ReentrantReadWriteLock 等提供了基础支撑。AQS的子类如下图所示。
AQS的内部结构
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
// 同步等待队列的头指针
private transient volatile Node head;
// 同步等待队列的尾指针
private transient volatile Node tail;
/**
* 同步器的状态。根据不同是实现有不同的含义,是AQS的核心。
* 比如 ReentrantLock 用这个state的值代表是否被加锁和重入的次数
*/
private volatile int state;
// 同步等待队列节点的定义
static final class Node {
// 头指针
volatile Node prev;
// 尾指针
volatile Node next;
// 节点中存放一个线程的引用
volatile Thread thread;
// ... 省略部分代码...
}
// CAS操作进行修改 state 的值
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
// ... 省略部分代码...
}
从代码中可以看出,AQS的内部有一个 volatile 声明的 state 和 两个指针,指向了AQS等待队列的头部和尾部。其结构大致如图:
AQS原理解析
- CAS + volatile
从上面的图中,我们可以看出来,AQS就是多个线程去竞争一个 state 占有权的一个类,state用 volatile修饰,是为了保证线程间可见,然后线程在竞争 state 的时候,用CAS操作保证了对 state 修改的原子性。 - CAS原理
// Unsafe.class 类中 compareAndSwapInt 的定义
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
从定义中我们可以看到,CAS方法是一个 native 方法,也就是说CAS操作是CPU原语支持的,保证了线程安全。
cas(Value, Offset, Expected, NewValue)
if Value== Expected
Value = NewValue
otherwise try again or fail
大概的意思就是当前值(Value)是我们期望的那个值(Expected),没有被其他线程修改过,那么就将它改为新的值(NewValue),否则重试或者失败。为了防止ABA问题(即一个线程将值从A改为B,然后另一个线程又将值从B改为A,这会让我们当前线程以为没有被其他线程操作过,这种ABA问题对于基本数据类型而言,结果没有什么影响,但是对于复杂的引用对象而言,我们是不知道这个对象内部是否被其他线程操作过什么的。为了解决这个问题,解决方案是为这个值带一个 Offset,值每被修改一次,这个Offset就修改一次,我们用 Value + Offset 的方式避免了 ABA 问题的出现)
我们可以从 Unsafe 类中的 getAndAddInt 来体会一下 ABA 问题的解决方案:
// Unsafe.class
/**
* 当对象o的值 和对象o在 给定offset偏移量(版本)下的值相同时,将当前对象设置为 o + delta
* @param o 当前对象
* @param offset 偏移量(版本)
* @param delta 要add的值
* @return int 添加后的结果
*/
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
// 获取对象o在给定offset偏移量(版本)下的值
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}