这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
前言
本文继续讲解SynchronousQueue队列的公平策略下的内部实现,不废话,直接看源码。
内部实现类
公平策略下的实现类TransferQueue。
TransferQueue
基于Transferer实现公平策略下的实现类TransferQueue,公平策略需要先进先出,这里queue也表明其结构特点,内部通过QNode类实现链表的队列形态,通过CAS操作更新链表元素。
有两种状态需要注意:
取消操作(被外部中断或者超时):item == this;
出队操作(已成功匹配,找到互补操作):next == this;
构造方法
头尾节点初始化操作
1 | ini复制代码 TransferQueue() { |
QNode
QNode即为队列的链表实现,其中的变量属性isData保存的是每次的操作动作而不仅仅是入队的值,入队操作以QNode保存,出队操作也是如此,变量则通过CAS操作更新。
1 | typescript复制代码 static final class QNode { |
变量部分
队头队尾元素引用设置,需要注意的是cleanMe节点的含义。
1 | java复制代码 // 队头 |
CAS操作
CAS更新变量操作
1 | typescript复制代码 // 尝试将nh更新为新的队头 |
transfer
入队和出队操作,都是用一个方法,即实现接口中的transfer方法来完成。
1 | scss复制代码 @SuppressWarnings("unchecked") |
阻塞等待唤醒(awaitFulfill)
在transfer相同类型操作时被调用,正常情况下(不算超时和中断)阻塞线程直到与之匹配的操作到来再继续执行。例如此时是入队操作,上次也是入队操作,在未设置超时时,这里可能需要自旋或阻塞等待一个出队操作来唤醒本次入队操作。
1 | scss复制代码 // 自旋或阻塞直到超时或被唤醒匹配上节点 |
clean方法
整体处理过程如下:
如果删除的不是尾节点,则用pred.casNext(s, s.next) 方式来进行清理;
如果删除的是队尾节点,若cleanMe为空,则将其前继节点pred更新为cleanMe, 为下次删除做准备;
如果cleanMe不为空,则根据cleanMe删除上次需要删除的节点, 然后将cleanMe置空, 如果此次pred非之前cleanMe,则cleanMe置为pred,为下一次删除操作做准备。
1 | ini复制代码 // 中断取消操作将pred节点代替s节点,修改前后节点之间的关联 |
本文转载自: 掘金