//加锁从 先看一下 acquire方法开始
private transient volatile Node head; //头节点 获取锁的线程节点
private transient volatile Node tail; //尾节点
Node 内部类
//共享
static final Node SHARED = new Node();
//独占
static final Node EXCLUSIVE = null;
//取消状态
static final int CANCELLED = 1;
//释放资源后唤醒的后继节点
static final int SIGNAL = -1;
//等待condition唤醒
static final int CONDITION = -2;
//工作于共享锁状态,需要向后传播,
//比如根据资源是否剩余,唤醒后继节点
static final int PROPAGATE = -3;
//等待状态,1,0,-1,-2,-3。
volatile int waitStatus;
//前驱节点
volatile Node prev;
//后继节点
volatile Node next;
//等待锁的线程
volatile Thread thread;
//等待条件的下一个节点,ConditonObject中用到
Node nextWaiter;
public final void acquire(int arg) {
//查看是否能获取锁,如果获取锁直接结束 ,未获取锁,调用 addWaiter 方法,Node为独占锁
if (!tryAcquire(arg) &&
//调用addWaiter 加入等待队列,并且加入acquireQueued 中 那么让我们看一下addWaiter()方法
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//1. 第一个方法 默认由子类实现
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
//加入队列中
private Node addWaiter(Node mode) {
//给当前线程创建一个Node
Node node = new Node(Thread.currentThread(), mode);
// 将tail Node 赋值给前驱节点 ,
Node pred = tail;
//如果pred不为null
if (pred != null) {
//将node的上一个节点设置为 pred,也就是tail
node.prev = pred;
//cas设置 期待值 pred 更新值 node 快速入队
if (compareAndSetTail(pred, node)) {
//如果cas成功,那么 tail (pred) 的下一个节点设置为 node
pred.next = node;
return node;
}
}
//如果 pred是null 或者设置失败 ,调用enq
enq(node);
return node;
}
//继续接下来的 enq
private Node enq(final Node node) {
//cas 加 自旋
for (;;) {
// 尾节点赋值给 t
Node t = tail;
//t 如果是 null 尾节点是 null 那么证明队列没有初始化
if (t == null) { // Must initialize
//初始化 设置一个虚假的头节点
if (compareAndSetHead(new Node()))
//头节点指向尾节点
tail = head;
} else {
//t 如果不是null 将 node 的 prev 设置为 tail
node.prev = t;
//进行设置尾节点 预估值 t 实际值 node 本来尾节点是 t 现在设置为 node
if (compareAndSetTail(t, node)) {
// 当前获取锁的节点的 next 设置为 node
t.next = node;
return t;
}
}
}
}
//继续
final boolean acquireQueued(final Node node, int arg) {
//是否失败 默认失败
boolean failed = true;
try {
//默认未中断
boolean interrupted = false;
//cas 加 自旋
for (;;) {
// 获取上一个在等待的节点
final Node p = node.predecessor();
//如果当前节点的上一个节点 p 如果是头节点, 那么当前节点 node就是老二, 可以尝试获取锁,尝试成功,则当前 节点 node 设置为头节点, 原头节点 p 引用设置为null,help gc
if (p == head && tryAcquire(arg)) {
//设置当前节点为头节点
setHead(node);
//p.next 设置为null 无指向的引用
p.next = null; // help GC
//设置为成功
failed = false;
return interrupted;
}
//如果 不是头节点, 或者锁没有获取成功, 调用 是否应该在等待队列 park
// 线程被唤醒之后,已经执行完 parkAndCheckInterrupt() 方法, 继续执行,因为再 for循环中,所以 继续拿当前界面去尝试,尝试失败,继续park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
//如果是失败了, 那么 取消当前节点
if (failed)
cancelAcquire(node);
}
}
//开始
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//pred 前驱节点 node 当前节点
int ws = pred.waitStatus;
//如果是 获取锁的线程 可以唤醒后续线程,那么直接true
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
//正常 可以安心去睡
return true;
//如果前置 pred 取消了
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
// 前置的前置节点 赋值给 前置节点, 并且赋值给 node 的前置节点, 一直找到 pred.waitStatus 小于等于 0的
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
//前置节点 的 next 设置为当前 节点
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
//如果是小于 0 设置尾 SIGNAL 需要唤醒后续节点
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
//在看一下 park 将该线程 等待
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
`
总结 : 先尝试默认获取锁,获取失败加入等待队列,等待队列中 如果还没有获取, 在等待 释放锁之后唤醒,继续抢占锁,抢占不到,继续睡
- 看一下释放锁
public final boolean release(int arg) {
//尝试释放锁, 返回 boolean 释放成功或者失败
if (tryRelease(arg)) {
//释放成功 ,头节点赋值给 h
Node h = head;
// head 或者 h 不为null 并且 h的等待状态不为 0
if (h != null && h.waitStatus != 0)
//可以唤醒其他线程
unparkSuccessor(h);
return true;
}
return false;
}
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
//head的 等待状态
int ws = node.waitStatus;
//小于 0
if (ws < 0)
//设置为 0
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//获取当前节点的next 节点
Node s = node.next;
//如果是 null 或者 状态 大于 0
if (s == null || s.waitStatus > 0) {
// s 赋值为 null
s = null;
// 从后向前循环
for (Node t = tail; t != null && t != node; t = t.prev)
//获取到 waitStatus 小于等于 0
if (t.waitStatus <= 0)
//t赋值给 s
s = t;
}
//s 不等于 null
if (s != null)
//唤醒s线程
LockSupport.unpark(s.thread);
}
总结 : 根据状态去唤醒下一个线程 如果下一个线程为null 那么从后向前循环 找到一个符合条件的线程唤醒