[关闭]
@eric1989 2016-02-13T02:38:14.000000Z 字数 1306 阅读 747

高性能并发双向队列算法

背景

在LRU的算法实现中,一个双向队列用来计算节点热度是不可少的。但是jdk自带的实现中,是一个单线程的双向队列实现。多线程的安全性则需要依靠锁来实现,性能很低。在这种情况下,开发设计了并发双向队列算法。主要目的是通过cas操作来屏蔽锁争夺。主要提供三个操作:a.添加节点到队列末尾。b.移动节点到队首。c.删除节点
由于将锁的力度降低到了每一个节点,所以在多线程并发操作下,性能会有很大的提高。

双向队列如下图,每一个节点均含有pre和next指针。并且队列具有head指针和tail指针。head指针和tail指针都指向一个初始的head节点。该节点仅作为标识,不具有其他作用。

基本操作

基本思想 : 对一个节点的操作,在于争夺尾节点的控制权;对于一个节点的删除或者移动操作,则在于争夺该节点和前置节点的控制权。对于当前节点和前置节点控制权的争夺,会使得写操作被顺序化,保证了正确性

将一个节点添加到尾节点

Created with Raphaël 2.1.2开始获取tail节点将节点状态进行cas从0切换到1设置目标节点状态为1(设置自身的状态,避免下一步移动tail指针的时候整个操作还没有完成,节点会被受到其他的干扰)将目标节点的next指针设置为null(如果有读取操作发生在tail解锁前,在读取到这里时就可以返回)tail节点的next指针设置为目标节点目标节点的pre指针设置为tail节点设置tail指针为目标节点,设置目标节点的前置节点的state为0设置目标节点状态为0结束yesno

将一个节点删除

Created with Raphaël 2.1.2开始 目标节点的标志位cas从0切换到1成功,否则自旋检测目标pre指针是否为null目标节点标志位设置为0.结束目标节点的前置节点的标志位cas从0切换到1成功,否则自旋目标节点是否是尾节点将前置节点的next指针设置为null将tail指针设置为前置节点将目标节点的pre指针设置为null将前置节点的标志位设置回0目标节点的标志位设置回0End将前置节点的next指针设置为后置节点将后置节点的pre指针设置为前置节点yesnoyesno

移动节点到队首

Created with Raphaël 2.1.2开始 目标节点的标志位cas从0切换到1成功,否则自旋目标节点的前置节点的标志位cas从0切换到1成功,否则自旋目标节点是否为尾节点将前置节点的next指针设置为null将tail指针设置为前置节点将前置节点的标志位设置为0将head节点的标志位cas从0切换到1成功,否则自旋将目标节点的next指针设置为head节点的后置节点将目标节点的pre指针设置为head节点将head节点的后置节点pre指针设置为目标节点将head节点的next指针设置为目标节点将目标节点的标志位设置为0将head节点的标志位设置为0结束将前置节点的next指针设置为后置节点将后置节点的pre指针设置为前置节点yesno

算法变种

不具有tail节点

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注