ConcurrentLinkedQueue

主要讲一下在JDK8中,ConcurrentLikedQueue是如何入队,出队的。

首先我们要明白,ConcurrentLikedQueue是一种安全的没有边界的基于链表的队列,有头节点head,尾结点tail。

类似于           ,上图是创建一个空的队列,只有head和tail节点,以下为源码:

public ConcurrentLinkedQueue() {
        head = tail = new Node<E>(null);
}

对于入队来说,我们要了解的是tail节点不一定是最后一个节点,这是非常重要的。一般来说,当tail节点的next不为空时,在队尾加入新节点,更新tail指向尾节点;当tail的next节点为空时,在队尾加入新节点,不更新tail的位置。

源码中有一个注释:Both head and tail are permitted to lag.  In fact, failing to update them every time one could is a significant optimization (fewer CASes). As with LinkedTransferQueue (see the internal documentation for that class), we use a slack threshold of two; that is, we update head/tail when the current pointer appears to be two or more steps away from the first/last node.
 大概的意思是说不用每次都更新头尾节点,这是一个非常重要的优化。 使用的松弛阈值为2; 也就是说,当当前指针距离第一个/最后一个节点有两个或更多节点的距离时,我们更新head/tail。

在入队的时候,我们就能够很容易的看到上述所描述tail的特点。

入队:

 /**
* Inserts the specified element at the tail of this queue.
* As the queue is unbounded, this method will never return {@code false}.
* 将指定的元素插入到此队列的末尾。因为队列是无界的,所以这个方法永远不会返回{@code false}。 * @return {@code true} (as specified by {@link Queue#offer})
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
checkNotNull(e);
final Node<E> newNode = new Node<E>(e); //入队前构建节点 //从尾结点开始入队
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) { //tail是尾结点
// p is last node
//如果p是尾结点,设置p节点的next为newNode
if (p.casNext(null, newNode)) { //如果新节点添加入尾节点后面
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
//成功的CAS是使e成为这个队列的一个元素,使newNode成为“活的”的线性化点。
if (p != t) // hop two nodes at a time一次跳转两个节点
casTail(t, newNode); // Failure is OK.
return true;
}
// Lost CAS race to another thread; re-read next
//丢失的CAS争用到另一个线程;重读next
}
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;
}
}

上述的offer(E e)方法,即是向队列尾部添加元素。

首先,入队前构建结点newNode,接下来无限for循环,保证入队成功,所以该方法返回总是true。

假设现在队列中有两个结点a,b,tail指向b。t->tail,p->t,如下图:

假设现在要添加一个c结点,那么会出现下图情况:

如果再添加一个D结点,

(1)因为p结点的后继结点q不为null,并且q也不等于p,所以经过判断后,p指向q,tail不变。如下图:

(2)q继续指向p的next结点,因为q为null,所以把d结点设置为p结点的next结点,因为p不指向t,所以把t指向为尾结点。如下图:

总结下来,我们发现,首先总会获取到尾结点,然后用CAS算法进行结点入队。

ConcurrentLinkedQueue (一)的更多相关文章

  1. 队列送券的实际应用--ConcurrentLinkedQueue并发队列

    1.TicketQueue.java--队列封装类,负责如下职责:a.把活动登记对象放入队列中b.从队列中获取活动登记对象,并派券 package com.datong.pear.ticket; im ...

  2. 【JUC】JDK1.8源码分析之ConcurrentLinkedQueue(五)

    一.前言 接着前面的分析,接下来分析ConcurrentLinkedQueue,ConcurerntLinkedQueue一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素 ...

  3. Java 线程 — ConcurrentLinkedQueue

    ConcurrentLinkedQueue 在考虑并发的时候可以先考虑单线程的情况,然后再将并发的情况考虑进来. 比如ConcurrentLinkedQueue: 先考虑单线的offer 再考虑多线程 ...

  4. Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue

    概要 本章对Java.util.concurrent包中的ConcurrentHashMap类进行详细的介绍.内容包括:ConcurrentLinkedQueue介绍ConcurrentLinkedQ ...

  5. [Java 基础] 并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法

    reference : http://www.cnblogs.com/linjiqin/archive/2013/05/30/3108188.html 在Java多线程应用中,队列的使用率很高,多数生 ...

  6. 并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法

    在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列(先进先出).Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQ ...

  7. 阻塞队列LinkedBlockingQueue和并发队列ConcurrentLinkedQueue

    LinkedBlockingQueue: public class LinkedBlockingQueue<E> extends AbstractQueue<E> implem ...

  8. CAS无锁算法与ConcurrentLinkedQueue

    CAS:Compare and Swap 比较并交换 java.util.concurrent包完全建立在CAS之上的,没有CAS就没有并发包.并发包借助了CAS无锁算法实现了区别于synchroni ...

  9. java线程控制、状态同步、volatile、Thread.interupt以及ConcurrentLinkedQueue

    在有些严格的系统中,我们需要做到干净的停止线程并清理相关状态.涉及到这个主题会带出很多的相关点,简单的总结如下: 我们知道,在java中,有一个volatile关键字,其官方说明(https://do ...

  10. java LinkedBlockingQueue和ConcurrentLinkedQueue的区别

    实现上看,两者都继承于AbstractQueue,但是ConcurrentLinkedQueue实现了Queue,而LinkedBlockingQueue实现了BlockingQueue,Blocki ...

随机推荐

  1. vmware装centos7 无法上网

    现象 使用ip address看不到ip地址 ping www.baidu.com无法ping通 解决方式: 1.设置网卡 vi /etc/sysconfig/network-scripts/ifcf ...

  2. nfs高可用

      一.简介 NFS是单点的,如果一个节点出现问题,那使用它挂载服务的都将出现问题.所以需要高可用,挂掉一台不影响.采用keepalived+rsync+inotify-tools 环境: ubunt ...

  3. HTTP协议复习

    HTTP请求/响应的步骤: 客户端连接到WEB服务器:浏览器与web服务器的HTTP端口建立一个TCP套接字连接,例如:http://www.baidu.com 发送HTTP请求:通过TCP套接字,客 ...

  4. CSS製作動畫效果(Transition、Animation、Transform)

    CSS 2D Transforms https://www.w3schools.com/css/css3_2dtransforms.asp CSS 3D Transforms https://www. ...

  5. Kubernetes 使用 ingress 配置 https 集群(十五)

    目录 一.背景 1.1 需求 1.2 Ingress 1.3 环境介绍 二.安装部署 2.1.创建后端 Pod 应用 2.2 创建后端 Pod Service 2.3.创建 ingress 资源 2. ...

  6. SpringBoot系列教程web篇之Freemaker环境搭建

    现在的开发现状比较流行前后端分离,使用springboot搭建一个提供rest接口的后端服务特别简单,引入spring-boot-starter-web依赖即可.那么在不分离的场景下,比如要开发一个后 ...

  7. LeetCode 946. 验证栈序列(Validate Stack Sequences) 26

    946. 验证栈序列 946. Validate Stack Sequences 题目描述 Given two sequences pushed and popped with distinct va ...

  8. [转帖]IBM报告:多国央行考虑发行数字货币 最快5年内问世

    IBM报告:多国央行考虑发行数字货币 最快5年内问世 https://news.cnblogs.com/n/646001/ DCEP 中国央行可能是第一家发布 数字货币的央行 DCEP 是基于 UTX ...

  9. Python生成流水线《无限拍卖》文字!

    话说,原文也是这样流水线生产的吧··· 代码 import random one_char_word=["烈","焰","冰"," ...

  10. rsync 使用

    rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件. rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分, ...