【JDK源码分析系列】AbstractQueuedSynchronizer 源码分析 -- 基本属性
【1】AbstractQueuedSynchronizer 整体架构
1. AQS 中队列只有两个 : 同步队列 + 条件队列,底层数据结构两者都是链表
2. 图中有四种颜色的线代表四种不同的场景,1、2、3 序号代表看的顺序
【2】AbstractQueuedSynchronizer 基本属性
【2.0】AbstractQueuedSynchronizer 的定义与说明
// 1. 提供了一种框架,自定义了先进先出的同步队列,让获取不到锁的线程能进入同步队列中排队;
// 2. 同步器有个状态字段,可以通过状态字段来判断能否得到锁,此时设计的关键在于依赖安全的 atomic value 来表示状态
// (虽然注释是这个意思,但实际上是通过把状态声明为 volatile,在锁里面修改状态值来保证线程安全的);
// 3. 子类可以通过给状态 CAS 赋值来决定能否拿到锁,可以定义那些状态可以获得锁,哪些状态表示获取不到锁
// (比如定义状态值是 0 可以获得锁,状态值是 1 就获取不到锁);
// 4. 子类可以新建非 public 的内部类,用内部类来继承 AQS,从而实现锁的功能;
// 5. AQS 提供了排它模式和共享模式两种锁模式,排它模式下:只有一个线程可以获得锁,
// 共享模式可以让多个线程获得锁,子类 ReadWriteLock 实现了两种模式;
// 6. 内部类 ConditionObject 可以被用作 Condition,通过 new ConditionObject () 即可得到条件队列;
// 7. AQS 实现了锁、排队、锁队列等框架,至于如何获得锁、释放锁的代码并没有实现,
// 比如 tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared、isHeldExclusively 这些方法,
// AQS 中默认抛 UnsupportedOperationException 异常,都是需要子类去实现的;
// 8. AQS 继承 AbstractOwnableSynchronizer 是为了方便跟踪获得锁的线程,可以帮助监控和诊断工具识别是哪些线程持有了锁;
// 9. AQS 同步队列和条件队列,获取不到锁的节点在入队时是先进先出,但被唤醒时,可能并不会按照先进先出的顺序执行;
// AQS 是个抽象类,就是给各种锁子类继承用的,AQS 定义了很多如何获得锁,如何释放锁的抽象方法,目的就是为了让子类去实现;
// 继承了 AbstractOwnableSynchronizer,AbstractOwnableSynchronizer 的作用
// 就是为了知道当前是那个线程获得了锁,方便监控用的;
// AbstractOwnableSynchronizer 类中 private transient Thread exclusiveOwnerThread; 属性用于描述当前获得锁的线程
// setExclusiveOwnerThread 方法用于设置当前获取锁的线程
// protected final void setExclusiveOwnerThread(Thread thread) {
// exclusiveOwnerThread = thread;
// }
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
【2.1】AbstractQueuedSynchronizer 简单属性
// 同步器的状态,根据当前状态进行判断是否可以获得当前锁
// 如果当前state是0,那么可以获得锁
// 可重入锁,每次获得锁+1,每次释放锁-1
private volatile int state;
// 自旋超时阀值,单位纳秒
// 当设置等待时间时才会用到这个属性
static final long spinForTimeoutThreshold = 1000L;
【2.2】AbstractQueuedSynchronizer 同步队列属性
同步队列:底层数据结构是一个双向链表,当多个线程都来请求锁时,某一时刻有且只有一个线程能够获得锁 (排它锁),那么剩余获取不到锁的线程,都会到同步队列中去排队并阻塞自己,当有线程主动释放锁时,就会从同步队列头开始释放一个排队的线程,让线程重新去竞争锁,所以同步队列的主要作用阻塞获取不到锁的线程,并在适当时机释放这些线程。
// 同步队列的头。
// 公平的锁先入先出。
private transient volatile Node head;
// 等待队列的尾
private transient volatile Node tail;
【2.3】AbstractQueuedSynchronizer 条件队列属性
条件队列:条件队列管理获取不到锁的线程,底层数据结构也是链表队列,但条件队列不直接和锁打交道,但常常和锁配合使用,是一定的场景下,对锁功能的一种补充。
private static final long serialVersionUID = 1173984872572414699L;
// 条件队列中第一个 node
private transient Node firstWaiter;
// 条件队列中最后一个 node
private transient Node lastWaiter;
【2.4】AbstractQueuedSynchronizer Node 属性
//Node 既是同步队列的节点,又是条件队列的节点,
//在入队的时候,用 Node 把线程包装一下,然后把 Node 放入两个队列中
static final class Node {
//node 是共享模式
/** 标志用于指示一个节点在共享模式下等待 */
static final Node SHARED = new Node();
//node 是排它模式
/** 标志用于指示一个节点在独占模式下等待 */
static final Node EXCLUSIVE = null;
/**
* 等待状态值,表示线程被取消
*
* 由于在同步队列中等待的线程等待超时或中断,需要从同步队列中取消等待
* 节点进入该状态后不会发生变化
*/
// 被取消
static final int CANCELLED = 1;
/**
* 后继结点的线程处于等待状态,而当前节点的线程如果释放了同步状态或者被取消,
* 将会通知后继节点,使后继节点的线程得以运行
*/
// SIGNAL 状态的意义:同步队列中的节点在自旋获取锁的时候,
// 如果前一个节点的状态是 SIGNAL,那么自己就可以阻塞休息了,否则自己一直自旋尝试获得锁
static final int SIGNAL = -1;
/**
* 节点在等待队列中,节点线程等待在Condition上,
* 当其他线程对Condition调用了Signal()方法后,
* 该节点将会从等待队列转移到同步队列中,加入到对同步状态的获取中
*/
// 表示当前 node 正在条件队列中,
// 当有节点从同步队列转移到条件队列时,状态就会被更改成 CONDITION
static final int CONDITION = -2;
/**
* 表示下一次共享式同步状态获取将会无条件地被传播下去
*/
// 无条件传播,共享模式下,该状态的进程处于可运行状态
static final int PROPAGATE = -3;
/**
* 等待状态变量
*
* volatile 作用简介 : java 线程内存模型将确保所有线程看到的该变量是一致的;
*/
// 表示当前节点的状态,通过节点的状态来控制节点的行为
// 普通同步节点,就是 0 ,条件节点是 CONDITION -2
volatile int waitStatus;
/**
* 指向同步队列中当前节点的前驱节点
*/
// 当前节点的前节点
// 节点 acquire 成功后就会变成 head
// head 节点不能被 cancelled
volatile Node prev;
/**
* 指向同步队列中当前节点的后继节点
*/
// 当前节点的下一个节点
volatile Node next;
// 当前节点的线程
volatile Thread thread;
// 在同步队列中,nextWaiter 并不真的是指向其下一个节点,我们用 next 表示同步队列的下一个节点,
// nextWaiter 只是表示当前 Node 是排它模式还是共享模式
// 但在条件队列中,nextWaiter 就是表示下一个节点元素
Node nextWaiter;
/**
* 该方法用于判断节点是否处于共享状态
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 该方法用于获取当前节点的前驱节点
* 在该方法中添加了空指针判断,在前驱节点为空时,抛出空指针异常;
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
/**
* 内部类 Node 的默认构造方法
*
* 用于创立初始化头结点或者共享节点
*/
Node() {
}
/**
* 内部类 Node 的构造方法
*
* 构造的节点指定等待队列中的节点
*/
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
/**
* 内部类 Node 的构造方法
*
* 构造的节点指定等待的状态
*/
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
【2.5】AbstractQueuedSynchronizer 一般方法
【2.5.0】AbstractQueuedSynchronizer 队列操作图示
【2.5.1】AbstractQueuedSynchronizer 相关 CAS 方法
/**
* CAS 方式设置同步状态;
*/
protected final boolean compareAndSetState(int expect, int update) {
/**
* Unsafe 类提供了硬件级别的原子操作,提供了一些绕开JVM的更底层功能,由此提高效率;
* compareAndSwapInt : 比较并交换 int 型变量
*
* 参数说明
* 参数包含 : 需要读写的内存位置(stateOffset)、进行比较的预期原值(expect)
* 和拟写入的新值(update);
* 处理方式 : 如果内存位置stateOffset的值与预期原值expect相匹配,
* 那么处理器会自动将该位置值更新为新值update;
* 否则处理器不做任何操作。
*/
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
/**
* CAS head field. Used only by enq.
*/
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
/**
* CAS tail field. Used only by enq.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
/**
* CAS waitStatus field of a node.
*/
private static final boolean compareAndSetWaitStatus(Node node,
int expect,
int update) {
return unsafe.compareAndSwapInt(node, waitStatusOffset,
expect, update);
}
/**
* CAS next field of a node.
*/
private static final boolean compareAndSetNext(Node node,
Node expect,
Node update) {
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
【2.5.2】AbstractQueuedSynchronizer 相关线程处理方法
private final boolean parkAndCheckInterrupt() {
//阻塞当前线程
LockSupport.park(this);
//中断当前线程
return Thread.interrupted();
}
【3】条件 (Condition)
【3.0】Condition 的定义与说明
// 1. 当 lock 代替 synchronized 来加锁时,Condition 就可以用来代替 Object 中相应的监控方法了,
// 比如 Object#wait ()、Object#notify、Object#notifyAll 这些方法
// 2. 提供了一种线程协作方式:一个线程被暂停执行,直到被其它线程唤醒
// 3. Condition 实例是绑定在锁上的,通过 Lock#newCondition 方法可以产生该实例
// 4. 除了特殊说明外,任意空值作为方法的入参,都会抛出空指针
// 5. Condition 提供了明确的语义和行为,这点和 Object 监控方法不同
public interface Condition {
【3.1】Object 的监视器方法与 Condition 接口对比
【3.2】Condition 常用方法以及描述
参考致谢
本博客为博主的学习实践总结,并参考了众多博主的博文,在此表示感谢,博主若有不足之处,请批评指正。
【1】Java并发编程的艺术