Java之集合(二十四)ConcurrentLinkedDeque
转载请注明源出处:http://www.cnblogs.com/lighten/p/7517454.html
1.前言
本章介绍并发队列ConcurrentLinkedDeque,这是一个非阻塞,无锁,无界 ,线程安全双端操作的队列。简单说就是ConcurrentLinkedQueue的升级版,在JDK7之后才提供。该队列也不允许空元素,而且size方法并不是常量时间,其需要遍历链表,此时并发修改链表会造成统计size不正确。同样,bulk操作和equal以及toArray方法不保证原子性。
2.ConcurrentLinkedDeque
2.1 实现原理
要明白ConcurrentLinkedDeque的实现原理,ConcurrentLinkedQueue的实现原理是基础。数据结构是对称双向链接的链表结构。通过两个方法最小化可见性写入的次数:1.通过单个CAS推进前面多个节点。2.混合对同一个内存位置可见和不可见的写入。
一个节点定义成包含前置节点pre、数据项item、后置节点next。当节点item!=null的时候视为节点还存活,当通过CAS设置item为null的时候,逻辑上该节点已经从集合中删除了。任何时候显然第一个节点的前置节点为null,其终结任何链表的从活着的结点开始的前置引用,最后一个节点同样的,其终结任何链表从活着的结点开始后面的引用。第一个节点和最后一个节点并不一定活着,而且总是能够相互到达。一个新元素原子添加是通过CAS设置前置引用或后置引用为null入队列。
活跃的结点定义为活着的结点和第一个或最后一个节点(不一定活着)。一个deque有两个节点引用:head和tail。头尾节点只是接近第一个或最后一个节点,第一个节点总是能够通过头结点的前置节点找到,最后一个节点类似。
删除节点有三个层次:
1.逻辑删除:CAS设置item为null,然后变成一个可以断开的结点
2.断开连接:删除一个非活跃节点,最终会被GC回收。断开的节点可能被迭代器无限制地访问。逻辑删除后节点还在链表上,通过第一个节点向后遍历或者通过最后一个节点向前遍历,并不保证结点已被逻辑删除,这样的结点仅能通过一个方向可达。
3.GC断开连接:使得断开连接更彻底,活跃的结点无法到达删除的结点。
当一个节点出队列,会断开所有非活跃节点的引用,自我链接是一个十分有效的方法。遍历的时候可以保证不会遍历到相同的元素,但是不保证能够看到后加入的元素。
2.2 数据结构

就是原理中所说的头尾节点和前后终止节点标志。Node的结构如下:

Node的基本方法如下:
casItem:CAS比较更新Item字段的值
lazySetNext:CAS设置next的值,不需要管原值
casNext:CAS比较更新next的值
lazySetPrev:CAS设置prev的值,不需要管原值
casPrev:CAS比较更新prev的值
2.3 基本操作
添加一个元素,都是通过LinkFirst或LinkLast完成的:

步骤如下描述:1.非空校验,创建节点。2.循环设置:头插入先找到当前头结点:1.判断是否被插队2个,是就重新找到头结点。2.判断当前头结点是否是前置终止符,是重新循环。3.p是头结点,设置新节点的next节点为p,再通过CAS设置p的前置节点,被插队失败就继续循环,成功时如果p不等于h意味着2个节点了,需要替换头结点。而后返回。这个步骤之前的队列中也介绍过类似的,并不是很难理解。唯一有疑问的就是PREV_TERMINATOR是什么时候设置的,在链表的构成时候并不存在该节点。注意,插入步骤并没有关心逻辑删除的结点,只关注了终止结点,即前终止结点的特点是其前置节点是其本身,后终止结点是后置节点是其本身。所以可能出现A-null-B的情况,当然从一端进另一端出是不会出现这种情况的,这是发生在一端入一端出。
取出一个元素:

过程很简单:先要找到第一个元素且不为null,取出该元素,该元素必须是活着的item不为null,并且本线程成功将其设置成null,才算数,断开这个节点。如果上面那边替换失败就意味着该节点已经被取出了,重新找其后继节点来处理。看似这个步骤没问题,但是仔细想想就会发现有些不对:一个队列中有AB元素,A元素出队列,1线程让A元素出队里失败被2线程抢先,找到A元素的后继节点是B,但是此刻又有3线程添加了C元素在B的前面,按照栈的后入先出的原则,C应该是要先出队列的,可是顺序却变成了B先出队列。所以这里要注意:push和pop作为堆栈使用,顺序可能会有问题(这个只是根据源码进行的推测,可能疏忽了什么导致推测有错,如果有错请在评论中留言)。这里要注意,由于整个队列可能出现A-null-B这种情况,实际上poll操作也不关心逻辑删除,遇到逻辑删除就跳过找下一个就好了,因为本身就可能是其它线程先取走了。整个顺序是不会改变的,把队列中出现的item为null的结点当做没看见就可以了,整个移除处理就是在unlink方法。
unlink方法有些长,这里直接说下其作用:如果取出节点是头结点,就移除其后面所有连续的逻辑删除节点(如A-null-null-B,unlinkA节点会定位到B最后丢弃中间的变成null-B,更新头尾和前置的终结标志,还有其它可能不再描述),如果取出的结点是尾结点,操作和头结点类似。如果是中间就找到前后非null的结点,都跳过,最后设置前后终结标志。
大体的实现过程就是这样,其它方法不描述。使用也就像一般的队列一样使用就可以了。
Java之集合(二十四)ConcurrentLinkedDeque的更多相关文章
- Java从零开始学二十四(集合工具类Collections)
一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二 ...
- Java开发学习(二十四)----SpringMVC设置请求映射路径
一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...
- Java之集合(二十六)ConcurrentSkipListMap
转载请注明源出处:http://www.cnblogs.com/lighten/p/7542578.html 1.前言 一个可伸缩的并发实现,这个map实现了排序功能,默认使用的是对象自身的compa ...
- Java学习笔记二十四:Java中的Object类
Java中的Object类 一:什么是Object类: Object类是所有类的父类,相当于所有类的老祖宗,如果一个类没有使用extends关键字明确标识继承另外一个类,那么这个类默认继承Object ...
- 夯实Java基础(二十四)——Java8新特征之Optional类
1.概述 对于Java程序员来说,到目前为止出现次数最多的应该是NullpointException,它是导致Java应用程序失败的最常见原因.之前处理空指针我们必须先通过条件先去判断,然后再确认是否 ...
- Java之集合(二十二)PriorityBlockingQueue
转载请注明源出处:http://www.cnblogs.com/lighten/p/7510799.html 1.前言 本章介绍阻塞队列PriorityBlockingQueue.这是一个无界有序的阻 ...
- Java基础(二十四)Java IO(1)输入/输出流
在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称为输出流. 输入流的指向称为源,程序从指向源的输入流中读取数据. 输出流的指向是字节要去的目的地, ...
- java 面向对象(二十四):interface:接口
interface:接口1.使用说明: 1.接口使用interface来定义 * 2.Java中,接口和类是并列的两个结构 * 3.如何定义接口:定义接口中的成员 * * 3.1 JDK7及以前:只能 ...
- Java之集合(二十五)ConcurrentHashMap
转载请注明源出处:http://www.cnblogs.com/lighten/p/7520808.html 1.前言 本章介绍使用的最频繁的并发集合类之一ConcurrentHashMap,之前介绍 ...
随机推荐
- linux week3
2.如何快速的回到 上⼀一次所在的位置 cd An argument of - is equivalent to $OLDPWD. cd - #cd $OLDPWD cd - #快速的回到 上 ...
- b2_trsd_EDSD_new
# -*- coding:utf-8 -*- import re ss="./data/" year = '17A' filename = ss+'EDSD%s.txt'%year ...
- ubuntu16.4中开启vncserver进行远程桌面
使用x11vnc作为vncserver端 1 安装x11vnc $ sudo apt-get update $ sudo apt-get install x11vnc 2 生成密码 $ x11vnc ...
- 20155323 2016-2017-2 《Java程序设计》第6周学习总结
20155323 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 串流:衔接数据的来源和目的地就是串流对象. I/O操作主要是指使用Java进行输入,输出操作 ...
- Win窗口坐标二维坐标与OpenGl的世界坐标系的之间的相互转换
Win窗口坐标二维坐标与OpenGl的世界坐标系的转换 几何处理管线擅长于使用视图和投影矩阵以及用于裁剪的视口把顶点的世界坐标变换为窗口坐标. 但是,在有些情况下,需要逆转这个过程.一种常见的情形是: ...
- visual studio 2015 rc &cordova -hello world
初始环境,用来看看书,电影,上上网的win8,所以一切从头开始. 1,首先还是装visual studio 2015 rc吧,目前只放出在线安装,所以要很长很长时间.不过有新闻说很快要实现中国网友至 ...
- 2014年誓言:干掉网页设计程序——Dreamweaver!
2014年誓言:干掉网页设计程序——Dreamweaver! 阅读: 评论: 作者:Rybby 日期: 来源:rybby.com 2014年,我写下誓言,用自己设计的在线网页设计工具“拉拉变” ...
- ggdl
\documentclass{article} \usepackage{geometry} \geometry{hmargin=1cm,vmargin=1cm} \usepackage{tikz} % ...
- eclipse中java build path下 allow output folders for source folders 无法勾选,该如何解决 eclipse中java build path下 allow output folders for source folders 无法勾选,
在创建maven工程时,在设置output folders时,总是勾选以后,老是自动恢复到原来的状态,对比其他的maven的工程发现是在创建maven时候选择的项目为pom,而不是war或者jar,将 ...
- A SQL to insert continuous values
I need a table to store all the working days. I dont like loop, so I tried sql. The following is the ...