/**
*
* 学习 AbstractQueuedSynchronizer
*
* 1. state是aqs的重要属性,说明锁的使用次数
* 2. CustomAbstractQueuedSynchronizer,存在 head 与 tail 属性,所以其本身就是一个链表。并没有使用集合
* 3. 双向链表(等待队列)
* 1. head 永远都是伪节点(thead = null)
* 2. tail 初始化时是伪节点(初始化时, head == tail),之后就不是了。
* 4. node的作用就是封装线程信息,然后并放到链表中排队
* 5. node节点有5种状态:
* 1. 用于双向链表(CANCELLED、SIGNAL、0)
* 2. 用于单向链表(CONDITION)
* 3. 用于共享锁(PROPAGATE)
* 6. 双向链表中 head与tail的节点状态永远是 0,中间节点的状态为 -1,被取消(无效/中断)的节点状态为 1
* 7. 挂起线程:LockSupport.pack(thread); 唤醒线程:LockSupport.unpack(thread)
* 8. 获取锁操作:acquire -> tryAcquire -> addWaiter -> acquireQueued(死循环) -> shouldParkAfterFailedAcquire
* -> parkAndCheckInterrupt -> LockSupport.park -> setHead(可以认为,删除唤醒节点)
* 9. 获取锁异常操作:cancelAcquire
* 10.取消锁操作:release -> tryRelease -> unparkSuccessor -> LockSupport.unpark
* 11. CustomAbstractQueuedSynchronizer类,是抽象类,但没有抽象方法。可以 new,但无法使用锁。
* 因为 TryAcquire 与 TrgRelease 方法,一个是获取锁,一个是释放锁。但默认都是报错。需要子类集成后重写方法。
* 12. 双向链表中是否可以不用head节点?
* 可以不用。
* 1.在设计之前就提出了伪节点的存在,
* 2.head节点的使用可以简化
* 13. 为什么是双向链表,而不是用单线链表?
* 因为在使用单线链表时,删除中间节点时,无法将node.prev.next 指向node.next。解决方法只能不断遍历,增加了很多无用操作。
* 而使用双向链表就没有这个问题
*
*
*
*
* 3. 条件队列(ConditionObject,内部类)
*
* 查对条件队列与同步队列
*/
标签:head,AQS,LockSupport,链表,并发,tail,源码,双向,节点
From: https://www.cnblogs.com/zz-1q/p/17840513.html