AbstractQueuedSynchronizer ,本文简称aqs,是java锁机制的基类
1 aqs的父类
aqs 的直接父类 AbstractOwnableSynchronizer aos 中的 私有变量 exclusiveOwnerThread 表示持有锁的线程
2 aqs中的队列
aqs, 基于fifo的等待队列,可支持 阻塞锁、信号量(semaphores) 。
包括两种 sync队列 由双向链表实现,组成Node有共享、排他两种模式,共享模式允许多个线程持有锁,排他模式只允许单个线程持有锁
monitor队列 由单项链表实现,组成Node只有排他模式
两种队列都是由Node节点组成的,每个node节点持有对应的线程
Node节点结构 sync队列 monitor队列
等待状态 waitStatus
前驱节点 prev --
后继节点 next --
对应线程 thread
下个等待节点 nextWaiter 用来表示共享、排他两种模式 用来表示下个节点
等待状态(waitStatus)有:
1 CANCELLED 值1 代表该节点对应的线程已被取消
2 SIGNAL 值-1 代表该节点的后继节点的线程需要唤醒(unparking)
3 CONDITION 值-2 代表该节点对应线程处于 等待池(wait on condition)
4 PROPAGATE 值-3 代表 下个共享节点 无条件传播
5 0 值0 代表当前节点
3 sync队列
结构 :
头节点 Node head
尾节点 Node tail
队列状态 int state 信号量Semaphore 通过该字段的值控制持有锁的线程数
CountdownLatch 通过该字段初始化coutdown线程数
ReentrantLock 通过该字段记录锁重入次数,判断锁的获得与释放
对应的方法有 三个 int getState() 获取state (持有锁的线程数、)
setState(int newState) 初始化state(允许的许可量)
boolean compareAndSetState(int expect, int update) 动态乐观更新(重入次数,剩余许可量等)
方法:
(1)入队 Node enq(final Node node)
入队方法中包括了 head tail 的初始化、node加入队尾两部分,通过cas方法 (乐观锁)的方式实现,如果初始化、node入队失败,代表其他线程同时初始化或入队成功,需要重试(放在for循环中),对应源码:
(2) 入队waiter Node addWaiter(Node mode)
入队waiter时,指定当前线程 是共享还是排他模式入队。
下图try the fast ,比直接 入队快在没有for循环。
(3)设置头结点
node设置为头结点,node对应线程出sync队列,null字段方便gc
(4) 唤醒后继节点 unparkSuccessor(Node node)
1 设置当前节点为 waitStatus 为0,
2 唤醒后继节点 或最近后继节点
(5) 释放(共享模式)
对 SIGNAL 节点,waitStatus置位0,唤醒后继或最近后继节点;
(6)设置头结点并 释放对0节点,waitStatus置为 PROPAGATE
(7) 取消获取 cancelAcquire(Node node)
1 找到node 最近 非取消的 前置节点 pred
2 设置node waitStatus 为 CANCELLED
3 如果node为队尾,node出队,pred设置为队尾
node不为队尾,pred不是队头, 设置pred waitStatus为SIGNAL ,
node的后置节点waitStatus<=0时, pred指向 node的后置节点
pred是队头,唤醒node
(8) 获取失败后等待 shouldParkAfterFailedAcquire(Node pred, Node node)
(9)获取 boolean acquireQueued(final Node node, int arg)
node获取的锁,如果前置节点是head,去获取
自中断
子类获取、释放锁时修改state(int)
支持 排他 共享两种模式,排他即独占,共享可限制最大数量