- AQS简介
- AQS子类需要实现的方法
- AQS构成
- AQS队列节点
- AQS队列
- 条件队列
- 操作
- 查询操作
- get操作(获取)
- getExclusiveQueuedThreads操作
- getFirstQueuedThread操作
- fullGetFirstQueuedThread操作
- getQueuedThreads操作
- getQueueLength操作
- getSharedQueuedThreads操作
- getWaitingThreads操作
- condition.getWaitingThreads操作
- getWaitQueueLength操作
- condition.getWaitingThreads操作
- has操作(判断有没有)
- hasQueuedPredecessors操作
- hasQueuedThreads操作
- hasWaiters操作
- condition.hasWaiters操作
- 插入操作
- AQS插入操作
- 条件队列插入操作
- Acquire操作(获取锁操作)
- acquire操作(获取独占锁操作)
- acquireQueued操作
- shouldParkAfterFailedAcquire操作
- cancelAcquire操作
- unparkSuccessor操作
- acquireInterruptibly操作(获取可中断锁操作)
- doAcquireInterruptibly操作
- acquireShared操作(获取共享锁操作)
- doAcquireShared操作
- setHeadAndPropagate操作
- doReleaseShared操作
- acquireSharedInterruptibly操作(获取共享可中断锁操作)
- doAcquireSharedInterruptibly操作
- tryAcquireNanos操作 (获取独占可超时锁操作)
- doAcquireNanos操作
- tryAcquireSharedNanos操作 (获取共享可超时锁操作)
- doAcquireSharedNanos操作
- Release操作(释放锁操作)
- release操作
- releaseShared操作
- AQS是 AbstractQueueSynchronizer 虚拟队列同步器,是一个虚拟类,子类只需实现其5个方法中的三个就可以构造一个可获取独占锁或获取共享锁的类,没有获取到锁的线程会进入队列排队
- 这个类负责实现排队操作,队列中每个节点内部都有一个阻塞的线程,队头的节点是获取锁的线程,队头节点负责唤醒后续一个节点
- 其父类 AbstractOwnableSynchronizer 负责记录和设置当前获取锁的线程
AbstractOwnableSynchronizer 源码可以看我这篇文章 AbstractOwnableSynchronizer - 光看AQS操作可能有些抽象,也不知道它在干嘛,可以看看其子类的实现如 ReentrantLock
ReentrantLock 源码可以看我这篇文章 ReentrantLock
| 方法名 | 作用 |
|---|---|
| boolean tryAcquire(int arg) | 尝试获取独占锁,没有成功则排队 |
| boolean tryRelease(int arg) | 尝试释放独占锁 |
| iint tryAcquireShared(int arg) | 尝试获取共享锁,没有成功则排队 |
| boolean tryReleaseShared(int arg) | 尝试释放共享锁 |
| boolean isHeldExclusively() | 判断当前线程是否独占锁 |
- SHARED 将该队列标记为共享模式即多个线程可以获取到锁,EXCLUSIVE 将该队列标记为独占模式即只有单个线程可以获取到锁
- CANCELLED、SIGNAL、CONDITION、PROPAGATE都是节点的状态值,它们会把值赋给waitStatus
- prev、next说明AQS是由双向链表实现的队列
- thread说明每个Node节点对应一个线程,说明有一个线程在里面阻塞并排队
- nextWaiter是下一个条件队列节点
- NEXT、PREV、THREAD、WAITSTATUS是变量句柄,是JDK9新特性,通过它们可以对应的变量进行CAS操作和原子操作,不需要再像以前把变量定义为原子类变量了,如NEXT可以对next进行CAS和原子性操作,如果想要达到这种效果只有把prev定义为AtomicReference< Node > 类型
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int ConDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
private static final VarHandle NEXT;
private static final VarHandle PREV;
private static final VarHandle THREAD;
private static final VarHandle WAITSTATUS;
}
AQS队列
- head就是队列的头节点,tail就是队列的尾节点,state在其子类实现一般理解为获取锁的次数
- STATE、HEAD、TAIL 是对应变量的变量句柄
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
private transient volatile Node head;
private transient volatile Node tail;
private volatile int state;
private static final VarHandle STATE;
private static final VarHandle HEAD;
private static final VarHandle TAIL;
}
条件队列
可以看出条件队列里面也是使用Node节点作为其组成,只是使用的是Node节点的nextWaiter属性,相当于单向链表
public class ConditionObject implements Condition, java.io.Serializable {
private transient Node firstWaiter;
private transient Node lastWaiter;
}
操作
查询操作
get操作(获取)
getExclusiveQueuedThreads操作
作用:获取队列中处于独占锁模式的线程列表
实现:从双向链表尾部开始查找,尾部查找原因在插入enq里面,如果Node节点不是共享节点,则取出节点中存放的线程并将其加入列表
public final CollectiongetFirstQueuedThread操作getExclusiveQueuedThreads() { ArrayList list = new ArrayList<>(); for (Node p = tail; p != null; p = p.prev) { if (!p.isShared()) { Thread t = p.thread; if (t != null) list.add(t); } } return list; }
作用:获取队列中第一个等待的线程
实现:如果头节点等于尾结点说明没有线程排队,否则执行fullGetFirstQueuedThread返回队头后面一个结点内部的线程,或者后续结点内部的线程
public final Thread getFirstQueuedThread() {
// handle only fast path, else relay
// 仅处理快速路径,否则为转发
return (head == tail) ? null : fullGetFirstQueuedThread();
}
fullGetFirstQueuedThread操作
- 连续检查两次,队头h不为空 ,且队头下一个节点s也不为空,且s的前一个节点为队头h,且s存储的线程也不为空,则返回队头下一个节点的线程st
- 为什么不返回队头节点内部的线程,因为队头节点内部的线程一般为null,为null表示已经获取到锁在运行了,不为null说明仍然在排队
- 如果以上条件不满足,则从队列尾部开始往前找,找到最靠近队头的一个内部线程不为空的节点,再返回该节点内部的线程
private Thread fullGetFirstQueuedThread() {
Node h, s;
Thread st;
if ( //队头不为空 且 队头下一个也不为空 且队头的下一个的前一个为队头 且存储的线程也不为空
((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null)
||
//队头不为空 且 队头下一个也不为空 且队头的下一个的前一个为队头 且存储的线程也不为空
((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null)
)
return st;
Thread firstThread = null;
// 则从队列尾部开始往前找,找到最靠近队头的一个内部线程不为空的节点
for (Node p = tail; p != null && p != head; p = p.prev) {
Thread t = p.thread;
if (t != null)
firstThread = t;
}
return firstThread;
}
getQueuedThreads操作
作用:获取队列中等待的线程集合
实现:从双向链表尾部开始查找,如果Node节点内部线程不为空,则取出节点中存放的线程并将其加入列表
public final CollectiongetQueueLength操作getQueuedThreads() { ArrayList list = new ArrayList<>(); for (Node p = tail; p != null; p = p.prev) { Thread t = p.thread; if (t != null) list.add(t); } return list; }
作用:获取队列中等待的线程数量
实现:从双向链表尾部开始查找,如果Node节点内部线程不为空,则计数器加1
public final int getQueueLength() {
int n = 0;
for (Node p = tail; p != null; p = p.prev) {
if (p.thread != null)
++n;
}
return n;
}
getSharedQueuedThreads操作
作用:获取队列中共享(共享锁)结点等待的线程集合
实现:从双向链表尾部开始查找,如果Node节点是共享结点且内部线程不为空,则取出节点中存放的线程并将其加入列表
public final CollectiongetWaitingThreads操作getSharedQueuedThreads() { ArrayList list = new ArrayList<>(); for (Node p = tail; p != null; p = p.prev) { if (p.isShared()) { Thread t = p.thread; if (t != null) list.add(t); } } return list; }
作用:获取条件队列中等待的线程集合
实现:从单向链表中往后查询,找到Node状态为CONDITION且其内部线程不为null的结点,取出内部线程放入集合,同步队列和条件队列都使用Node结点作为其元素
public final Collectioncondition.getWaitingThreads操作getWaitingThreads(ConditionObject condition) { if (!owns(condition)) throw new IllegalArgumentException("Not owner"); return condition.getWaitingThreads(); }
从Node结点的nextWaiter单向链表实现的条件队列往后找,状态为CONDITION且内部线程Thread不为空的结点,取出其内部线程并放入集合
protected final CollectiongetWaitQueueLength操作getWaitingThreads() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); ArrayList list = new ArrayList<>(); for (Node w = firstWaiter; w != null; w = w.nextWaiter) { if (w.waitStatus == Node.CONDITION) { Thread t = w.thread; if (t != null) list.add(t); } } return list; }
作用:获取条件队列中等待的线程数量
实现:从单向链表中往后查询,找到Node状态为CONDITION且其内部线程不为null的结点,计数器加1
public final int getWaitQueueLength(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitQueueLength();
}
condition.getWaitingThreads操作
从Node结点的nextWaiter单向链表实现的条件队列往后找,如果结点状态为CONDITION则计数器加一
protected final int getWaitQueueLength() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int n = 0;
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
++n;
}
return n;
}
has操作(判断有没有)
hasQueuedPredecessors操作
作用:判断队列中有没有排队的线程
实现:
- 取出头节点h,如果不为空,且其后续一个结点s也不为空,则判断s内部线程是不是当前线程,如果不是,说明有线程在排队,返回true
- 如果结点s为空,则需要从双向链表尾部往前找,找到最靠近头节点h且不为空且其状态小于等于0的结点设为s,状态小于等于0说明不是CANCELLED取消状态,判断这个新的s的内部线程是否为当前线程如果不是,说明有线程在排队
public final boolean hasQueuedPredecessors() {
Node h, s;
if ((h = head) != null) {
if ((s = h.next) == null || s.waitStatus > 0) {
s = null;
for (Node p = tail; p != h && p != null; p = p.prev) {
if (p.waitStatus <= 0)
s = p;
}
}
if (s != null && s.thread != Thread.currentThread())
return true;
}
return false;
}
hasQueuedThreads操作
作用:判断队列中有没有状态小于等于0的结点
public final boolean hasQueuedThreads() {
for (Node p = tail, h = head; p != h && p != null; p = p.prev)
if (p.waitStatus <= 0)
return true;
return false;
}
hasWaiters操作
作用:判断队列中有没有排队的线程
实现:必须要获取错才能执行,判断条件队列中有无结点状态为CONDITION
public final boolean hasWaiters(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.hasWaiters();
}
condition.hasWaiters操作
protected final boolean hasWaiters() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
return true;
}
return false;
}
插入操作
AQS插入操作
- 获取尾节点,如果尾节点不为空,将node节点的prev设置为尾节点,这已经把双向链表的前向连接好了
- 用CAS将尾节点设为新插入的节点,如果成功则将以前的尾节点的后向连接练好,可以看到前向连接是先连好的,所以这也是AQS队列的几乎所有查询操作都从尾节点开始往前找的原因
- 如果尾节点为空,则初始化队列即创建一个节点将其同时设为头节点和尾节点
private Node enq(Node node) {
for (;;) {
// 获取尾节点
Node oldTail = tail;
// 如果尾节点不为空
if (oldTail != null) {
// 将node节点的prev设置为尾节点
node.setPrevRelaxed(oldTail);
// CAS改变尾节点,若此时尾节点还是oldTail,则将尾节点设为node
if (compareAndSetTail(oldTail, node)) {
// 如果上面操作成功则将以前的尾节点的后一个节点设为新节点
// 否则自旋直至设置node为尾节点成功
oldTail.next = node;
return oldTail;
}
}
// 如果尾节点为空,说明队列为空
else {
// 创建一个队列,即将头和尾设置为同一个新创建的节点
// 然后进入自旋,只有在上面插入成功了才会跳出循环
initializeSyncQueue();
}
}
}
条件队列插入操作
- 可以看出条件队列插入和AQS插入两者差别不大,但有两个差别,如下
- Node node = new Node(mode) 其实是创建一个节点,该节点的prev、next全为null,如果是独占模式连nextWaiter属性也为空,如果是共享模式nextWaiter属性设为传入的mode,还有一个操作是把node节点的thread设为当前线程
- AQS插入返回的是尾节点,条件队列插入返回的是当前节点
- 可以条件队列插入其实会影响AQS队列,相对于也在AQS队列尾部插入一个Node节点,只是该Node节点的nextWaiter属性有效,可以通过这个属性找到条件队列下一个节点
private Node addWaiter(Node mode) {
//Node.EXCLUSIVE 传入null 则创建null 则在下面初始化头尾节点
//Node.SHARED 传入 new Node() 是nextWaiter为 new Node()
Node node = new Node(mode);
for (;;) {
// 获取尾节点
Node oldTail = tail;
// 如果尾节点不为空
if (oldTail != null) {
// CAS改变尾节点,若此时尾节点还是oldTail,则将尾节点设为node
node.setPrevRelaxed(oldTail);
// 使用CAS设置node为尾节点
if (compareAndSetTail(oldTail, node)) {
// 如果上面操作成功则将以前的尾节点的后一个节点设为新节点
// 否则自旋直至设置node为尾节点成功
oldTail.next = node;
return node;
}
} else {
// 创建一个队列,即将头和尾设置为同一个新创建的节点
// 然后进入自旋,只有在上面插入成功了才会跳出循环
initializeSyncQueue();
}
}
}
Acquire操作(获取锁操作)
acquire操作(获取独占锁操作)
- 尝试获取锁,如果没有成功,则先执行addWaiter往条件队列添加节点,但同时影响AQS队列,由于是独占模式nextWaiter属性为null
- acquireQueued方法自旋判断传入的Node结点(刚刚使用addWaiter创建并返回的)是否排队到队头,到队头再次尝试获取锁,如果还没成功使用CAS尝试将Node状态设为SIGNAL并当将当前线程阻塞,等待前一个结点的唤醒
- arg 一般传入的是获取锁的次数
- selfInterrupt 是如果没有获取到锁且在自旋阻塞等待过程中收到中断信号,则进行自我中断
public final void acquire(int arg) {
// 如果获取锁没有成功 且
if (!tryAcquire(arg) &&
// 先执行addWaiter添加条件队列节点(同时影响AQS队列),独占模式nextWaiter为空
// 然后自旋方法检测排队是否到队头,到了尝试获取锁,没有则设置状态为SIGNEL,并阻塞当前线程
// 自旋方法排队是否到队头,到了尝试获取锁,没有则设置状态为SIGNEL
// 设置成功进行阻塞
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 上面是死循环方法而且嵌套在if语句条件中,如果出循环且返回true说明检测到中断状态需要进行自我中断
// 进行自我中断
selfInterrupt();
}
acquireQueued操作
- 循环(自旋),获取当前结点前一结点,当前结点已经是经过addWaiter添加到双向链表了所以会有前一结点,如果前一结点是头节点,才尝试获取锁,获取成功将当前结点设为头节点,将当前结点中thread属性置空,说明头节点就是获取到锁的结点,且获取到锁的结点thread属性为空
- 没有获取到锁执行shouldParkAfterFailedAcquire方法将当前结点的前一结点p的状态设为SIGNAL,如果p状态大于0,说明前一结点需要释放,则往前找一个状态小于0正常的结点,重新连接前面结点和当前结点,如果前面操作成功阻塞当前线程并返回是否需要中断
- 出现任何错误,则移除双向链表中的node结点
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
for (;;) {
// 返回node的上一个节点
// 循环后如果node上一个节点改变,则会抛出异常
final Node p = node.predecessor();
// tryAcquire 尝试以独占模式获取
if (p == head && tryAcquire(arg)) {
// 设置该节点为头节点
setHead(node);
// 之前的头节点让GC回收
p.next = null; // help GC
return interrupted;
}
// 独占没有获取成功
// 则尝试设为p的状态为SIGNAL,如果p为要释放节点,则p将往前移
if (shouldParkAfterFailedAcquire(p, node))
// 位操作 | 相当于 逻辑||
// 方便的阻塞方法,然后检查是否中断。
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
// 取消获得
// 从队列中移除该节点
cancelAcquire(node);
// 判断是否要添加中断标记
if (interrupted)
selfInterrupt();
throw t;
}
}
shouldParkAfterFailedAcquire操作
- 获取前一结点的状态,如果为SIGNAL则返回
- 如果状态大于0说明是CANCELLED状态,则前一节点要被取消,则再往前寻找无须被取消的结点,将其与当前结点node相连
- 使用CAS将前一结点状态设为SIGNAL,可能设置不成功,不管设置成功与否都会返回false,直到外部下一次自旋时再返回true
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
do {
// 跳过中间waitStatus大于0的节点
// pred = pred.prev;
// node.prev = pred;
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 设置状态为SIGNAL
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}
cancelAcquire操作
1.取消当前节点,如果当前结点为空则直接返回
2.如果当前节点存在,则先将其内部线程置空,再往前找状态不大于0的节点存为pred,pred的后一个节点也是要取消的节点存为predNext,设置当前节点状态为CANCELLED
3.使用CAS将尾节点设为前面有效节点pred,成功后再将pred.next置为空
4.CAS操作没有成功则说明此时尾节点已经被替换,说明可能新传入一个节点,此时要判断两个情况,如果pred已经是队头则调用unparkSuccessor唤醒node的后一个节点因为node要被取消了,如果pred不是队头还在排队,则将node下一个节点设为pred的下一个节点,则可以将node从双向链表中移除了
private void cancelAcquire(Node node) {
if (node == null)
return;
//内部线程置空
node.thread = null;
//前找状态不大于0的节点存为prev
Node pred = node.prev;
while (pred.waitStatus > 0)
// pred = pred.prev;
// node.prev = pred
node.prev = pred = pred.prev;
Node predNext = pred.next;
// 设置当前节点状态为CANCELLED
node.waitStatus = Node.CANCELLED;
// 使用CAS将尾节点设为前面有效节点pred,成功后再将pred.next置为空
if (node == tail && compareAndSetTail(node, pred)) {
pred.compareAndSetNext(predNext, null);
}
// CAS操作没有成功则说明此时尾节点已经被替换,说明可能新传入一个节点
else {
int ws;
if (pred != head &&
// 先前一个节点状态为SIGNAL 或
//状态小于0且先前一个节点状态CAS设为SIGNAL(-1)成功且先前一个节点线程不为空
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
pred.thread != null) {
// 获取节点后一个节点
Node next = node.next;
// 如果节点后一个节点非空,且状态小于等于0,则将pred节点的下一个节点设为next节点
if (next != null && next.waitStatus <= 0)
pred.compareAndSetNext(predNext, next);
}
// 如果pred已经是队头
else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
unparkSuccessor操作
- 获取当前节点状态,如果小于0则是功能节点,将其设为0为普通节点,SIGNAL为-1表示节点负责唤醒后续节点
- 判断node后续节点是否有效,即不为空且状态不为CANCELLED
- 无效则从尾节点开始找最靠近node的有效节点,并解除其内部线程阻塞
private void unparkSuccessor(Node node) {
//获取当前节点状态
int ws = node.waitStatus;
// 如果小于0则是功能节点,将其设为0为普通节点
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
Node s = node.next;
// 寻找node后续的有效节点,即不为空且状态不为CANCELLED
if (s == null || s.waitStatus > 0) {
s = null;
// 无效则从尾节点开始找最靠近node的有效节点
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
if (s != null)
// 解除其内部线程阻塞
LockSupport.unpark(s.thread);
}
acquireInterruptibly操作(获取可中断锁操作)
- 先检测线程是否打上了中断标志,打上了则抛出异常
- 如果尝试获取锁没有成功,则进行可中断自旋
public final void acquireInterruptibly(int arg)
throws InterruptedException {
//先检测线程是否打上了中断标志,打上了则抛出异常
if (Thread.interrupted())
throw new InterruptedException();
//尝试获取锁没有成功,则
if (!tryAcquire(arg))
// 自旋 循环尝试获取锁,只不过循环一次会阻塞一次,
doAcquireInterruptibly(arg);
}
doAcquireInterruptibly操作
和acquireQueued类似
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
acquireShared操作(获取共享锁操作)
tryAcquireShared尝试获取共享锁没有成功,则自旋获取
public final void acquireShared(int arg) {
// 尝试获取共享锁没有成功
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
doAcquireShared操作
- 和acquireQueued类似,但往双向链表添加的Node节点的nextWaiter属性不再为空
- 当前一节点为头节点才尝试获取锁,获取成功则调用setHeadAndPropagate方法,否则阻塞
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean interrupted = false;
try {
for (;;) {
final Node p = node.predecessor();
// 前一节点为头节点
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
return;
}
}
if (shouldParkAfterFailedAcquire(p, node))
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
} finally {
if (interrupted)
selfInterrupt();
}
}
setHeadAndPropagate操作
设置node为头节点,并调用doReleaseShared方法唤醒node后续节点
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
setHead(node);
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
doReleaseShared操作
- 取出头节点,如果头节点状态为SIGNAL,说明用来唤醒后续节点,则先用CAS将头节点状态设为0,再唤醒后续节点,如果CAS设置失败,则进入下一次循环
- 如果头节点状态为0,则将其设为PROPAGATE传播状态,如果CAS设置失败,则进入下一次循环
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
continue;
//唤醒节点的后续节点(如果存在)。
unparkSuccessor(h);
} else if (ws == 0 &&
!h.compareAndSetWaitStatus(0, Node.PROPAGATE))
continue;
}
if (h == head)
break;
}
}
acquireSharedInterruptibly操作(获取共享可中断锁操作)
尝试获取共享锁没有成功则调用doAcquireSharedInterruptibly自旋
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
doAcquireSharedInterruptibly操作
和doAcquireShared差别不大
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
tryAcquireNanos操作 (获取独占可超时锁操作)
如果获取独占锁成功则返回,否则自旋获取锁,有超时返回的功能,返回true表示获取成功,返回false表示超时
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 如果获取锁成功则返回
return tryAcquire(arg) ||
// 否则自旋获取锁,有超时返回的功能
doAcquireNanos(arg, nanosTimeout);
}
doAcquireNanos操作
- 和acquireQueue操作差不多,只是多了计时操作,如果超时则调用cancelAcquire释放节点
- 而且每循环一次也会阻塞,和前面的一直阻塞不同,这是调用LockSupport.parkNanos(this, nanosTimeout),进行定时阻塞,超时则解除阻塞
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L) {
cancelAcquire(node);
return false;
}
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
tryAcquireSharedNanos操作 (获取共享可超时锁操作)
如果获取共享锁成功则返回,否则自旋获取锁,有超时返回的功能,返回true表示获取成功,返回false表示超时
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquireShared(arg) >= 0 ||
doAcquireSharedNanos(arg, nanosTimeout);
}
doAcquireSharedNanos操作
- 和doAcquireShared操作差不多,只是多了计时操作,如果超时则调用cancelAcquire释放节点
- 而且每循环一次也会阻塞,和前面的一直阻塞不同,这是调用LockSupport.parkNanos(this, nanosTimeout),进行定时阻塞,超时则解除阻塞
private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.SHARED);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
return true;
}
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L) {
cancelAcquire(node);
return false;
}
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
Release操作(释放锁操作)
release操作
tryRelease是子类实现的,如果释放独占锁成功,则判断头节点是否为空,不为空则判断头结点状态,如果头结点状态为0,说明已经唤醒过后续结点了,不需要再唤醒,否则则调用unparkSuccessor唤醒后续结点
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
releaseShared操作
tryRelease是子类实现的,如果释放共享锁成功,则调用doReleaseShared()唤醒后续结点,doReleaseShared代码上面有介绍
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}



