ConcurrentLinkedQueue (一)
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 (一)的更多相关文章
- 队列送券的实际应用--ConcurrentLinkedQueue并发队列
1.TicketQueue.java--队列封装类,负责如下职责:a.把活动登记对象放入队列中b.从队列中获取活动登记对象,并派券 package com.datong.pear.ticket; im ...
- 【JUC】JDK1.8源码分析之ConcurrentLinkedQueue(五)
一.前言 接着前面的分析,接下来分析ConcurrentLinkedQueue,ConcurerntLinkedQueue一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素 ...
- Java 线程 — ConcurrentLinkedQueue
ConcurrentLinkedQueue 在考虑并发的时候可以先考虑单线程的情况,然后再将并发的情况考虑进来. 比如ConcurrentLinkedQueue: 先考虑单线的offer 再考虑多线程 ...
- Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue
概要 本章对Java.util.concurrent包中的ConcurrentHashMap类进行详细的介绍.内容包括:ConcurrentLinkedQueue介绍ConcurrentLinkedQ ...
- [Java 基础] 并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法
reference : http://www.cnblogs.com/linjiqin/archive/2013/05/30/3108188.html 在Java多线程应用中,队列的使用率很高,多数生 ...
- 并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法
在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列(先进先出).Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQ ...
- 阻塞队列LinkedBlockingQueue和并发队列ConcurrentLinkedQueue
LinkedBlockingQueue: public class LinkedBlockingQueue<E> extends AbstractQueue<E> implem ...
- CAS无锁算法与ConcurrentLinkedQueue
CAS:Compare and Swap 比较并交换 java.util.concurrent包完全建立在CAS之上的,没有CAS就没有并发包.并发包借助了CAS无锁算法实现了区别于synchroni ...
- java线程控制、状态同步、volatile、Thread.interupt以及ConcurrentLinkedQueue
在有些严格的系统中,我们需要做到干净的停止线程并清理相关状态.涉及到这个主题会带出很多的相关点,简单的总结如下: 我们知道,在java中,有一个volatile关键字,其官方说明(https://do ...
- java LinkedBlockingQueue和ConcurrentLinkedQueue的区别
实现上看,两者都继承于AbstractQueue,但是ConcurrentLinkedQueue实现了Queue,而LinkedBlockingQueue实现了BlockingQueue,Blocki ...
随机推荐
- SQLServer replace函数
declare @name char(1000) --注意:char(10)为10位,要是位数小了会让数据出错 set @name='ssssfcfgghdghdfcccs' select repla ...
- [E2E_L7 51CTO]初步接触OpenVINO提供的例子(win+vs)
一.例子编译 1.运行 C:\Program Files (x86)\IntelSWTools\openvino_2019.1.148\bin\setupvars.bat 这步需要win平台下安装py ...
- Python之schedule用法,类似linux下的crontab
# -*- coding: utf-8 -*- # author:baoshan import schedule import time def job(): print("I'm work ...
- IDEA中不编译src/main/java目录下的*.xml文件
使用idea构建maven项目时不编译src/main/java目录下写的mapper.xml文件,这是找到pom.xml文件,在<build>节点下添加如下代码: <!-- map ...
- EasyNVR摄像机网页H5全平台无插件直播流媒体播放服务二次开发之接口鉴权示例讲解
背景需求 EasyNVR的使用者应该都清楚的了解到,EasyNVR一个强大的功能就是可以进行全平台的无插件直播.主要原因在于rtsp协议的视频流(默认是需要插件才可以播放的)经由EasyNVR处理可以 ...
- NODE_ENV=production 环境变量设置
"start": "NODE_ENV=production node ./bin/www"
- mysql查询之上升的温度,有趣的电影,超过5名学生的课,大国,反转性别, 换座位
最近发现一个网站 力扣 查看 上面有很多算法和数据库的题目,做了一下,发现自己平时都疏忽了,因此边做边记录下来 1.上升的温度 给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天 ...
- com.alibaba.fastjson使用介绍
首先,介绍一下fastjson.fastjson是由alibaba开源的一套json处理器.与其他json处理器(如Gson,Jackson等)和其他的Java对象序列化反序列化方式相比,有比较明显的 ...
- 第07组 Beta冲刺(3/4)
队名:秃头小队 组长博客 作业博客 组长徐俊杰 过去两天完成的任务:学习了很多东西 Github签入记录 接下来的计划:继续学习 还剩下哪些任务:后端部分 燃尽图 遇到的困难:自己太菜了 收获和疑问: ...
- C++和C API调用
c++是C的超集,不可避免的要兼容C的特性,C++在C基础山的拓展部分叫做C with class,同时C++有自己特有的属性比如模板template. C并不完全是C++的子集. 那么如何在C/C+ ...