文章目录
enq 结点入队
//结点入队,必要的时候需要初始化
private Node enq(final Node node) {
//死循环;直到成功入队
for (;;) {
//获取同步队列的尾结点
Node t = tail;
//若尾结点为空,则初始化
if (t == null) {
//以CAS 模式设置头结点
if (compareAndSetHead(new Node()))
//首尾相连
tail = head;
} else {
//若队列已经初始化,则将要要新结点的前继结点设置成旧的尾结点
node.prev = t;
//CAS设置尾结点
if (compareAndSetTail(t, node)) {
//设置旧尾结点的后继引用为新尾结点
t.next = node;
//返回尾结点;循环唯一出口
return t;
}
}
}
}
addWaiter 添加结点
/**
* 当前线程或给定模式的结点入队
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 尝试快速入队,失败了则走 enq 方法
//获取尾结点
Node pred = tail;
if (pred != null) {
//设置旧尾结点为新结点的前继结点
node.prev = pred;
//CAS 设置尾结点
if (compareAndSetTail(pred, node)) {
//设置旧尾结点的后继引用为新结点
pred.next = node;
//返回入队的结点
return node;
}
}
//结点入队,具体看上面
enq(node);
//返回入队的结点
return node;
}
unparkSuccessor 唤醒后继结点
/**
* 唤醒后继(如果存在的话)
*/
private void unparkSuccessor(Node node) {
//获取当前结点的等待状态;如果小于0,则 CAS 更新成 0
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//获取当前结点的后继引用
Node s = node.next;
//后继引用为 null 或 被取消(大于0 就是取消了)
if (s == null || s.waitStatus > 0) {
//置空后继引用
s = null;
//从尾部向前推进获取第一个没有取消的结点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
//唤醒线程
LockSupport.unpark(s.thread);
}
setHeadAndPropagate 设置头结点和后继结点状态
/**
* 设置头结点并且后继引用可直接获取锁
*/
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();
}
}
cancelAcquire 取消尝试
/**
* 取消正在尝试获取锁的线程
*/
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
// 获取当前结点的前继结点(备注:前继1号,不然后面注释不好写),忽略取消状态的结点
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 获取 前继1号 的后继引用,可能是取消状态的结点引用
Node predNext = pred.next;
// 设置当前结点的状态为 取消 状态
node.waitStatus = Node.CANCELLED;
// 若当前结点是尾结点则自我毁灭,并且CAS设置前继1号为 尾结点
if (node == tail && compareAndSetTail(node, pred)) {
// CAS设置前继1号的后继引用为 null
compareAndSetNext(pred, predNext, null);
} else {
int ws;
if (pred != head
//设置前继1号的状态为 唤醒后继引用
&& ((ws = pred.waitStatus) == Node.SIGNAL ||(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL)))
&& pred.thread != null) {
//获取当前结点的后继引用
Node next = node.next;
if (next != null && next.waitStatus <= 0)
//CAS 设置 前继1号的后继引用
compareAndSetNext(pred, predNext, next);
} else {
//猜想:走到这一步,前继加点可能是头结点
//唤醒线程
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
shouldParkAfterFailedAcquire
/**
* 字面直接翻译下:
* 检查并更新无法获取的节点的状态。如果线程应该阻塞,则返回true。
* 这是所有采集回路中的主要信号控制。要求 pred == node.prev
*
* 简单说下:判断是否可以挂起当前线程
* @param pred 前继结点的状态
* @param node 结点
* @return 如果线程阻塞返回 true,反之 false
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
// 可以直接唤醒后继引用,所以放心吧
return true;
if (ws > 0) {
// 过滤取消的结点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//waitStatus 可能是 0 或者 -3;无论是哪个都可以选择 置成 唤醒后继结点 状态
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
selfInterrupt 自我中断
/**
* 自我中断(吓死爹了,是个狠角色)
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
parkAndCheckInterrupt
/**
* 阻塞当前线程并检查线程是否中断
*/
private final boolean parkAndCheckInterrupt() {
//阻塞线程
LockSupport.park(this);
//线程是否中断
return Thread.interrupted();
}
acquireQueued
/**
* 以 独占 不中断模式获取锁
* 用于 获取 和条件等待队列方法 中
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取参数 node 的前一个结点
final Node p = node.predecessor();
//判断是否是第一个节点
// tryAcquire:独占方式获取,后面重点说
if (p == head && tryAcquire(arg)) {
// 设置头结点
setHead(node);
// 将上一个head结点的后继清空,为了帮助垃圾收集
p.next = null;
failed = false;
//返回中断的状态, 整个循环执行到这里才是出口
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
//判断是否可以挂起并且当前线程阻塞
interrupted = true;
}
} finally {
//确保如果失败就取消获取
if (failed)
cancelAcquire(node);
}
}
doAcquireInterruptibly 中断的方式获取锁
/**
* 可中断的方式获取锁
* 大部分代码和上面 acquireQueued 方法类似,所以只在不一样的地方加注释
*/
private void doAcquireInterruptibly(int arg) throws InterruptedException {
//包装当前线程成独占模式结点入队列
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
//tryAcquire:独占方式获取,后面重点说
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
// 获取锁成功后直接返回
return;
}
// 线程被唤醒后如果发现中断请求就抛出异常
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
doAcquireNanos 超时获取锁
/**
* 以限定超时时间模式获取锁
* 大部分代码和上面 acquireQueued 方法类似,所以只在不一样的地方加注释
*/
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);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
//tryAcquire:独占方式获取,后面重点说
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return true;
}
//看时间是否到了,超时时间到了就返回
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0) {
return false;
}
//判断是否可以挂起
//超时时间大于自旋时间;spinForTimeoutThreshold:自旋超时阈值,默认 1000
if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) {
//将当前线程挂起一段时间, 之后再自己醒来
LockSupport.parkNanos(this, nanosTimeout);
}
//在获取锁的期间收到中断请求就抛出异常
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
doAcquireShared 不中断共享锁
/**
* 以 共享 不中断模式获取锁
* 注意和 acquireQueued 的区别
* 上面有的注释就不在写了,原谅我偷会懒,(*^▽^*)
*/
private void doAcquireShared(int arg) {
//将当前线程以共享模式包装进队列
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
//tryAcquireShared:共享的方式获取,后面重点说
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null;
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
release 释放锁
//释放锁
public final boolean release(int arg) {
//尝试释放锁
if (tryRelease(arg)) {
//获取头结点
Node h = head;
//头结点不为空并且等待状态不等于0就去唤醒后继引用
if (h != null && h.waitStatus != 0) {
//唤醒后继引用
unparkSuccessor(h);
}
return true;
}
return false;
}
/**
* 以共享的模式释放锁
*/
private void doReleaseShared() {
for (;;) {
//获取头结点引用
Node h = head;
//判断队列是否已经初始化了
if (h != null && h != tail) {
//获取头结点引用的状态,若是 唤醒后继引用 状态,便将状态置为 0
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
// 醒来吧,沉睡的战士
unparkSuccessor(h);
}
//若头结点的转态是 0 ,则设置状态为 后继引用 可直接获取锁
else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue;
}
if (h == head)
//结束循环
break;
}
}
还有一些方法没有列出,大部分都能在上面注释中找到对应的解释。