转载请注明源出处: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的更多相关文章

  1. Java从零开始学二十四(集合工具类Collections)

    一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二 ...

  2. Java开发学习(二十四)----SpringMVC设置请求映射路径

    一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...

  3. Java之集合(二十六)ConcurrentSkipListMap

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7542578.html 1.前言 一个可伸缩的并发实现,这个map实现了排序功能,默认使用的是对象自身的compa ...

  4. Java学习笔记二十四:Java中的Object类

    Java中的Object类 一:什么是Object类: Object类是所有类的父类,相当于所有类的老祖宗,如果一个类没有使用extends关键字明确标识继承另外一个类,那么这个类默认继承Object ...

  5. 夯实Java基础(二十四)——Java8新特征之Optional类

    1.概述 对于Java程序员来说,到目前为止出现次数最多的应该是NullpointException,它是导致Java应用程序失败的最常见原因.之前处理空指针我们必须先通过条件先去判断,然后再确认是否 ...

  6. Java之集合(二十二)PriorityBlockingQueue

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7510799.html 1.前言 本章介绍阻塞队列PriorityBlockingQueue.这是一个无界有序的阻 ...

  7. Java基础(二十四)Java IO(1)输入/输出流

    在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称为输出流. 输入流的指向称为源,程序从指向源的输入流中读取数据. 输出流的指向是字节要去的目的地, ...

  8. java 面向对象(二十四):interface:接口

    interface:接口1.使用说明: 1.接口使用interface来定义 * 2.Java中,接口和类是并列的两个结构 * 3.如何定义接口:定义接口中的成员 * * 3.1 JDK7及以前:只能 ...

  9. Java之集合(二十五)ConcurrentHashMap

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7520808.html 1.前言 本章介绍使用的最频繁的并发集合类之一ConcurrentHashMap,之前介绍 ...

随机推荐

  1. Linux下安装配置 Jdk1.6+Tomcat6+Apache2.2.x+jk_mod1.2 详解

    本篇以Redhat AS5,内核为Linux 2.6.18-8.el5 为例,其中Redhat/Fedora系列基本一致,其他Linux或者版本均可以参考. STEP 1 软件下载:1. jdk1.6 ...

  2. 删除重复的feature vba VS 删除重复的feature python

    VBA: Sub deleteDuplicatedFeature() Dim app As IApplication Set app = Application Dim pMxDocument As ...

  3. 使用系统的CoreLocation定位

    ////  ViewController.m//  LBS////  Created by tonnyhuang on 15/8/28.//  Copyright (c) 2015年 tonnyhua ...

  4. hdu 5015 233矩阵快速幂

    http://acm.hdu.edu.cn/showproblem.php?pid=5015 需要构造一个 n+2 维的矩阵. 就是要增加一维去维护2333这样的序列. 可以发现 2333 = 233 ...

  5. 【Win2D】【译】Win2D 快速入门

    原文链接:http://microsoft.github.io/Win2D/html/QuickStart.htm 快速入门 这是 Win2D 的快速入门教程,将会介绍 Win2D 中的基本功能.你将 ...

  6. 仿建设银行APP首页效果

    仿建设银行APP首页效果 下载地址: http://pan.baidu.com/s/1eRMYEzC 下载后需要解压,解压密码联系:390980233  收费88元 HTML+JS实现,下载即可试用. ...

  7. Simple Package Tool 学习

    Simple Package Tool 学习   1.getattr内置函数 getattr(object, name[, default]) python Packages.py install - ...

  8. .NET Core MemoryCache缓存获取全部缓存键

    在Core中不能使用原HttpRuntime.Cache缓存,改为MemoryCache(Microsoft.Extensions.Caching.Memory). 现MemoryCache新版为2. ...

  9. supervisord 启动失败 Error: Another program is already listening on a port that one of our HTTP serve...

    Linux系统中 Supervisor 配置守护进程: 启动Supervisor 服务语句: supervisord -c /etc/supervisor/supervisord.conf 这个过程可 ...

  10. css 可拖拽列表

    <!DOCTYPE HTML> <html><head> <meta charset="UTF-8"> <title>d ...