如果某线程加锁失败,他会把自己封装成一个Node,并会加入队列(双向链表),阻塞等待,别人释放锁。前面的内容接上一节内容。
1、AbstractQueuedSynchronizer类
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
尝试加锁失败,走以下逻辑
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
2、AbstractQueuedSynchronizer类
private Node addWaiter(Node mode) {
// 将当前线程封装了一个Node
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
//一开始pred和tail肯定为null
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
分析:
1)将当前线程封装了一个Node
Node node = new Node(Thread.currentThread(), mode);
2)下面这行代码其实就是将上面构造的节点添加到双向队列中去。
enq(node);
点击enq(node),进入如下代码
3、AbstractQueuedSynchronizer类
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
1)一开始t肯定为null,第一轮循环如下分支
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
这第一轮主要是构造了一个空Node
2)点击compareAndSetHead(new Node())进入如下代码
3)二轮之后的循环就会走这里
else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
4)点击compareAndSetTail(t, node)
5)通过下面这两句就将空节点(其实就是头节点)和新构建的节点连接起来了。
node.prev = t;
。。。。。。。。
t.next = node;
4、AbstractQueuedSynchronizer类
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
分析:
1)这里的参数update为上面传入的空节点(new Node())。
2)headOffset -> 在AQS类里,head变量所在的位置。CAS判断,head变量是否为null,如果是null,就将head设置为空Node节点
5、AbstractQueuedSynchronizer类
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
1)尝试比较tail变量是否为t,如果为t的话,那么tail指针就指向node。
6、AbstractQueuedSynchronizer类
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取到node的上一个节点
// prev指针指向的节点
final Node p = node.predecessor();
// 这个地方,其实会再次调用tryAcquire方法尝试加锁
// 如果加锁成功,其实是会将线程2对应的Node从队列中移除
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果说再次尝试加锁失败了
// 那么此时会判断一下,是否需要将当前线程挂起,阻塞等待
// 如果是需要的话,此时就会使用park操作挂起当前线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
分析:
1)这里的参数实际上为:线程2代表的Node,1。
2)点击setHead(node),剋看到代码如下:
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
这一段代码和下面的这一行,其实是:将线程2对应的节点清空,然后将头结点指过来。原来的头节点废掉。
setHead(node);
3)第一轮循环执行下面这行代码是返回false的。第二轮开始就返回true了。
shouldParkAfterFailedAcquire(p, node)
4)点击如下代码进入
parkAndCheckInterrupt())
7、AbstractQueuedSynchronizer类
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 {
// 将空Node的waitStatus设置为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
分析:
1)参数pred为空node
2)刚开始ws=0,执行else片段。将空Node的waitStatus设置为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
3)返回false到外层调用方法,第二次循环进来时会执行如下代码片段,并返回true
if (ws == Node.SIGNAL)
8、AbstractQueuedSynchronizer类
private final boolean parkAndCheckInterrupt() {
// LockSupport的park操作,就是将一个线程进行挂起,不让你动了
// 必须得有另外一个线程来对当前线程执行unpark操作,唤醒挂起的线程
LockSupport.park(this);
//试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,
//第二次再调用时中断状态已经被清除,将返回一个false。
return Thread.interrupted();
}
9、AbstractQueuedSynchronizer类
上面的代码执行完后,又到了第1步。
public final void acquire(int arg) {
// 先尝试加锁
// 如果加锁失败,addWaiter()方法将自己挂到队列中去
// 接着acquireQueued()方法负责park操作挂起当前线程,阻塞等待
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
10、一张图总结

724

被折叠的 条评论
为什么被折叠?



