ConcurrentLinkedQueue是一个基于链表的无界线程安全队列,非阻塞实现方式,先进先出,适合高并发的场景。

非阻塞的性能较好,采用CAS,避免加锁的时间,保证数据一致性。

采用“wait-free”算法实现。

(此部分源码看的比较吃力,很多不懂的地方,还有很多不知道的地方,希望不要误导读者,有好的文章之类的,希望能推荐下,谢谢)

定义

ConcurrentLinkedQueue继承AbstractQueue,实现 Queue, Serializable接口。内部通过链表实现。

ConcurrentLinkedQueue链表节点Node的数据item是volatile类型的,next节点也是volatile类型的。

默认构造一个空的ConcurrentLinkedQueue,head=tail= new Node(null)

源码分析

jdk1.7.0_71

add(E)方法

添加元素到队列尾部,实现是用offer,下面会说offer方法。

1
2
3
public boolean add(E e) {
return offer(e);
}

offer(E)方法

添加元素到队列尾部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public boolean offer(E e) {
checkNotNull(e);
//创建新节点
final Node<E> newNode = new Node<E>(e);

//循环开始,tail赋值给t,t赋值给p,此处是死循环,保证该入队操作能够一直重试,直到入队成功
for (Node<E> t = tail, p = t;;) {
//p的next赋值给q
Node<E> q = p.next;
//如果q是null,说明tail的next是null,tail指向的是队列尾部,所以tail的next应该始终是null,此处表示p是最后一个节点
if (q == null) {
// p是尾节点,则p的next节点是要入队列的节点
//cas操作,若失败表示其他线程对尾节点进行了修改,重新循环
//将p(p指向tail)的next指向新节点,若成功,进入if语句
if (p.casNext(null, newNode)) {
//cas操作成功后,判断p是否等于t,p不等于t,设置newNode为新的尾节点,p不等于t表示什么?(此处有不明白,希望高手帮帮忙。)
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
return true;
}
// p和q相等(这部分不是太理解,希望高手帮忙下)
}
else if (p == q)
// We have fallen off list. If tail is unchanged, it
// will also be off-list, in which case we need to
// jump to head, from which all live nodes are always
// reachable. Else the new tail is a better bet.
p = (t != (t = tail)) ? t : head;
else
// Check for tail updates after two hops.
p = (p != t && t != (t = tail)) ? t : q;
}
}

poll()方法

删除并返回头部元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public E poll() {
//设置循环标记
restartFromHead:
for (;;) {
for (Node<E> h = head, p = h, q;;) {
E item = p.item;
//表头数据不为null,cas操作设置表头数据为null成功进入if
if (item != null && p.casItem(item, null)) {
//p不等于h,队列头发生了变化,更新队列头为p,返回原来队列头的item
if (p != h) // hop two nodes at a time
updateHead(h, ((q = p.next) != null) ? q : p);
return item;
}
//队列头下一个节点为null,更新头尾p返回null
else if ((q = p.next) == null) {
updateHead(h, p);
return null;
}
else if (p == q)
continue restartFromHead;
else
p = q;
}
}
}

peek()方法

返回队列头部的元素,跟poll方法类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public E peek() {
restartFromHead:
for (;;) {
for (Node<E> h = head, p = h, q;;) {
E item = p.item;
if (item != null || (q = p.next) == null) {
updateHead(h, p);
return item;
}
else if (p == q)
continue restartFromHead;
else
p = q;
}
}
}

size()方法

需要遍历队列,不推荐使用,尽量使用isEmpty()

1
2
3
4
5
6
7
8
9
public int size() {
int count = 0;
for (Node<E> p = first(); p != null; p = succ(p))
if (p.item != null)
// Collection.size() spec says to max out
if (++count == Integer.MAX_VALUE)
break;
return count;
}

参考

http://www.infoq.com/cn/articles/ConcurrentLinkedQueue

http://www.cnblogs.com/skywang12345/p/3498995.html

ConcurrentLinkedQueue简介的更多相关文章

  1. 15.并发容器之ConcurrentLinkedQueue

    1.ConcurrentLinkedQueue简介 在单线程编程中我们会经常用到一些集合类,比如ArrayList,HashMap等,但是这些类都不是线程安全的类.在面试中也经常会有一些考点,比如Ar ...

  2. J.U.C并发框架源码阅读(十)ConcurrentLinkedQueue

    基于版本jdk1.7.0_80 java.util.concurrent.ConcurrentLinkedQueue 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL ...

  3. 并发容器之ConcurrentLinkedQueue

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  4. Java集合容器简介

    Java集合容器主要有以下几类: 1,内置容器:数组 2,list容器:Vetor,Stack,ArrayList,LinkedList, CopyOnWriteArrayList(1.5),Attr ...

  5. Java 理论与实践: 非阻塞算法简介——看吧,没有锁定!(转载)

    简介: Java™ 5.0 第一次让使用 Java 语言开发非阻塞算法成为可能,java.util.concurrent 包充分地利用了这个功能.非阻塞算法属于并发算法,它们可以安全地派生它们的线程, ...

  6. 死磕 java集合之ConcurrentLinkedQueue源码分析

    问题 (1)ConcurrentLinkedQueue是阻塞队列吗? (2)ConcurrentLinkedQueue如何保证并发安全? (3)ConcurrentLinkedQueue能用于线程池吗 ...

  7. ConcurrentLinkedQueue源码解读

    1.简介 ConcurrentLinkedQueue是JUC中的基于链表的无锁队列实现.本文将解读其源码实现. 2. 论文 ConcurrentLinkedQueue的实现是以Maged M. Mic ...

  8. Java并发编程原理与实战三十五:并发容器ConcurrentLinkedQueue原理与使用

    一.简介 一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素进行排序.队列的头部 是队列中时间最长的元素.队列的尾部 是队列中时间最短的元素.新的元素插入到队列的尾部,队列 ...

  9. 【JUC源码解析】ConcurrentLinkedQueue

    简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ...

随机推荐

  1. rails将类常量重构到数据库对应的表中之三

    经过博文之一和之二的重构,貌似代码表现的还不错,正常运行和test都通过鸟,但是,感觉告诉我们还是有什么地方不对劲啊!究竟是哪里不对劲呢?我们再来好好看一下. 我们把数据库表中的支付方式集合直接放在实 ...

  2. Java不走弯路教程(4.Client-Server模式(1)-Server)

    4.Client-Server模式(1)-Server 在上一章中,我们完成了MyDataBase.java的编写,类似于一个简单的数据库功能,提供了用户验证,查询操作. 在本章中,我们将继续扩展这个 ...

  3. OpenLayers3中wfs的属性查询

    var vector = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), u ...

  4. RunTime运行时在iOS中的应用之UITextField占位符placeholder

    RunTime运行时机制 runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API. 在我们平时编写的Objective-C代码中, 程序运行过程时, 其实最终 ...

  5. <mate name="viewport">移动端设置详解

    <meta name="viewport" content="width=device-width,height=device-height,initial-sca ...

  6. ABAP Open SQL 分页查询

    分页查询是一个常见需求,特别是在web相关的开发当中. 让人意外的是,google搜索abap paging query,查到的结果似乎都指出需要使用native SQL来实现相关功能:使用百度搜索 ...

  7. 学习MQ(三) 一个实例

    学习MQ(三) 一个实例. 现在有两台机器A和B,分别安装了MQ6.0,我要通过MQ进行A和B之间的双向通信. 我打算分两步,第一步:实现A到B的数据传输. 在A上: 1.创建队列管理器 QM_100 ...

  8. java中内存的使用

    一个java运行起来执行代码,主要的内存消耗有这几块: 1.堆 2.栈 :栈是每个线程一个的,是以消耗的内存是内存大小*线程数,当线程数特多时候需要小心 . 3.直接内存:主要是通道时候的缓存,在内存 ...

  9. centos安装nginx(针对一哥们的博客进行的详细补充(用红色字体标出了补充部分))

    centos安装nginx 原文地址:http://www.cnblogs.com/leechenxiang/p/5402960.html 一.什么是nginx 是一个C语言开发的HTTP反向代理服务 ...

  10. Java多线程:线程间通信之volatile与sychronized

    由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信. Java为线程间通信提供了三个相关的关键字volatile, synchronized ...