并发之AQS源码学习

发布时间 2023-11-18 15:00:30作者: 之士咖啡
/**
 *
 * 学习 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,内部类)
 *
 * 查对条件队列与同步队列
 */