AQS源码解析
比如有3个线程获取锁 我们以Lock来做分析,去看AQS的源码
A B C 3个线程
A线程是第一个 会被标记为独占线程 当然默认是非公平的
setExclusiveOwnerThread(Thread.currentThread());
exclusiveOwnerThread = thread;
/**
* The current owner of exclusive mode synchronization.
独占模式同步的当前所有者。
此时链表头部尾部没有节点
*/
private transient Thread exclusiveOwnerThread;
B线程获取锁时会走acquire(1);
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
selfInterrupt(); //线程中断
}
1.分析tryAcquire(arg)
2.分析 addWaiter(Node.EXCLUSIVE))
3.分析 acquireQueued
4.分析 selfInterrupt
5. 总结
tryAcquire
//这个方法现在看起来其实就是去判断该线程是否是独占线程
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread(); //当前线程
//getState 可能会为0 也可能会为1
//0代表可以获取 1代表已被获取
int c = getState(); //0
if (c == 0) {
//设置独占线程
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread() //当前线程是否等于独占锁) {
int nextc = c + acquires; //c +1 1+1=2 lock支持可重入的 重入一次+1
if (nextc < 0) // overflow 什么时候会出现? 我觉得不会出现吧
throw new Error("Maximum lock count exceeded"); //超过最大锁计数 没见过
setState(nextc); //重新设置值
return true;
}
return false;
}
addWaiter
private Node addWaiter(Node mode) {
//mode是一个空的 用于指示节点正在独占模式下等待的标记
Node node = new Node(Thread.currentThread(), mode); //把当前线程设置一个节点
// Try the fast path of enq; backup to full enq on failure
// 尝试enq的快速路径;故障时备份到完整enq
Node pred = tail; //此时tail为空
if (pred != null) { //这块C线程会走
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node); //执行enq
return node;
}
---------------------- enq -----------------------------------------------
/**
我们来看方法的描述
将节点插入队列,必要时进行初始化。见上图。
*/
//当B线程进来 既是头结点也是尾结点
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
if (compareAndSetHead(new Node())) //设置头节点 这是第二个争抢的线程会设置为头
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) { //设置尾结点
t.next = node;
return t;
}
}
}
}
shouldParkAfterFailedAcquire 失败后是否应暂停
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; //
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
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.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
acquireQueued
/**
以独占不间断模式获取已在中的线程
排队。用于条件等待方法以及获取。
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true; // 失败
try {
boolean interrupted = false; //中断
for (;;) { //死循环
final Node p = node.pred ecessor();
//在此时你会看见做判断
//就说明在这个节骨眼上他还有机会不被阻塞,可以获取独占资源,因为可能其他的都已经被释放了
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// LockSupport.park(this); 阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;//这块唤醒会继续执行循环 但是我自己debug都是直接return了
}
} finally {
if (failed)
cancelAcquire(node);
}
}
cancelAcquire 这块实际上我并没有debug到
Cancels an ongoing attempt to acquire. 取消正在进行的获取的尝试。
//移除节点
private void cancelAcquire(Node node) {
if (node == null) //node节点为空
return;
node.thread = null; //thread等于null
// Skip cancelled predecessors
//跳过取消的前置任务
Node pred = node.prev; //前节点
while (pred.waitStatus > 0) //前节点大于0 死循环
node.prev = pred = pred.prev; //不太明白用意
//predNext是要取消分片的明显节点。以下案例将
//如果失败,在这种情况下,我们输掉了比赛与另一个取消
//或信号,因此无需采取进一步行动。
Node predNext = pred.next;
//在这里可以使用无条件写而不是CAS。
//在这个原子步骤之后,其他节点可以跳过我们。
//以前,我们不受其他线程的干扰。
node.waitStatus = Node.CANCELLED; //waitStatus值,指示线程已取消
//如果我们是尾巴,就把自己移走。
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
//如果后继者需要信号,尝试设置pred的下一个链接
//所以它会得到一个。否则唤醒它传播。
int ws;
if (pred != head &&
((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)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
其实还有一个比较重要 什么时候被唤醒的 我想lock.unlock
把独占取消唤醒节点