根据现在等待队列中的节点状态,p == head是返回true的,然后就是tryAcquire(arg)了,由于线程A已经释放了锁,那现在的线程B自然就能获取到锁了,所以tryAcquire(arg)也会返回true。
设置队列头线路B拿到锁后,会调用setHead(node)自己设置为队列的头:
private void setHead(Node node) { head = node; node.thread = null; node.prev = null; }调用setHead(node)后队列会发生些变化 :
移除上一个节点setHead(node)执行完后,接着按上一个节点完全移除:
p.next = null;此时的队列:
线程B 释放锁线程B 释放锁的流程与线程A基本一致,只是当前队列中已经没有需要唤醒的线程,所以不需要执行代码去唤醒其他线程:
if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; }h != null && h.waitStatus != 0这里的h.waitStatus已经是0了,不满足条件,不会去唤醒其他线程。
总结文中通过自定义一个CustomLock类,然后通过查看AQS源码来学习AQS的部分原理。通过完整的走完锁的获取、释放两个流程,加深对AQS的理解,希望对大家有所帮助。
欢迎关注我的公众号:架构文摘,获得独家整理120G的免费学习资源助力你的架构师学习之路!
公众号后台回复arch028获取资料: