1.    引言

在并发编程中我们有时候需要使用线程安全的队列。

如果我们要实现一个线程安全的队列有两种实现方式:一种是使用阻塞算法,另一种是使用非阻塞算法。

使用阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两个锁(入队和出队用不同的锁)等方式来实现,

非阻塞的实现方式则可以使用循环CAS的方式来实现,本文让我们一起来研究下如何使用非阻塞的方式来实现线程安全队列ConcurrentLinkedQueue的。

2.    ConcurrentLinkedQueue的介绍

ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,

当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。

入队列就是将入队节点添加到队列的尾部

tail.casNext(null, n)   CAS算法,往tail的Next 设入队节点n。

tail.casTail(tail, n)   CAS算法,把入队节点n 标记为tail 。

01 public boolean offer(E e) {
02  
03        if (e == null)
04  
05          throw new NullPointerException();
06  
07       Node</e><e> n = new Node</e><e>(e);
08  
09       for (;;) {
10  
11          Node</e><e> t = tail;
12  
13          if (t.casNext(null, n) && casTail(t, n)) {
14  
15             return true;
16  
17          }
18  
19       }
20  
21     }

这个方法没有任何锁操作。线程安全完全由CAS操作和队列的算法来保证。整个算法的核心是for循环,这个循环没有出口,直到尝试成功,这也符合CAS操作的流程。

ConcurrentLinkedQueue使用时,应当注意的地方:

查看ConcurrentLinkedQueue的API ,

.size() 是要遍历一遍集合的,性能慢,所以尽量要避免用size而改用 isEmpty()

ConcurrentLinkedQueue并发队列的一个demo:
先建立一个测试pojo,Log.java两个字段,加上get、set方法
private Date date;
private String value;

然后建立队列类,如下:
/**
 * 用于记录日志的队列,ConcurrentLinkedQueue <br/>
 * 此队列按照 FIFO(先进先出)原则对元素进行排序,详见J2SE_API或JDK
 * @author RSun
 * 2012-2-22下午05:05:19
 */
public class SystemLogQueue {

private static Queue<Log> log_Queue;
static{
if (null == log_Queue) {
log_Queue = new ConcurrentLinkedQueue<Log>(); //基于链接节点的无界线程安全队列
}
}

/** 初始化创建队列 **/
public static void init() {
if (null == log_Queue) {
log_Queue = new ConcurrentLinkedQueue<Log>(); //基于链接节点的无界线程安全队列
}
}

/**
* 添加到队列方法,将指定元素插入此队列的尾部。
* @param log Log对象
* @return 成功返回true,否则抛出 IllegalStateException
*/
public static boolean add(Log log) {
return (log_Queue.add(log));//由于是无界队列(21亿个元素),基本上可以保证一直添加
}
/** 获取并移除此队列的头 ,如果此队列为空,则返回 null */
public static Log getPoll() {
return (log_Queue.poll());
}
/** 获取但不移除此队列的头;如果此队列为空,则返回 null **/
public static Log getPeek() {
return (log_Queue.peek());
}
/** 判断此队列是否有元素 ,没有返回true **/
public static boolean isEmpty() {
return (log_Queue.isEmpty());
}
/** 获取size,速度比较慢 **/
public static int getQueueSize() {
return (log_Queue.size());
}

public static void main(String[] args) {
System.out.println("队列是否有元素:" + !isEmpty());
Log log = new Log();
log_Queue.add(log);

System.out.println("队列是否有元素:" + !isEmpty());
Log log2 = new Log();
log2.setDate(new Date());
log2.setValue("哈哈哈");
log_Queue.add(log2);
System.out.println("队列元素个数:" + getQueueSize());

Log l = getPeek();
System.out.println("\n获取队列数据:" + l.getValue() + "---" + l.getDate());
System.out.println("队列元素个数:" + getQueueSize());

for (int i = 0; i < 2; i++) {
Log l2 = getPoll();
if(l2 != null){
System.out.println("\n获取队列数据并删除:" + l2.getValue() + "---" + l2.getDate());
}
System.out.println("队列元素个数:" + getQueueSize());
}
结果: // 队列是否有元素:false // 队列是否有元素:true // 队列元素个数:2 // 获取队列数据:null---null // 队列元素个数:2 // 获取队列数据并删除:null---null // 队列元素个数:1 // 获取队列数据并删除:哈哈哈---Thu Nov 15 13:58:02 CST 2012 // 队列元素个数:0
} }

转载于:https://www.cnblogs.com/my376908915/p/6759756.html

深入理解java:2.3.4. 并发编程concurrent包 之容器ConcurrentLinkedQueue(非阻塞的并发队列---循环CAS)...相关推荐

  1. JAVA 并发编程实践 - 原子变量与非阻塞同步机制 笔记

    2019独角兽企业重金招聘Python工程师标准>>> 非阻塞算法: 利用底层的源自机器指令(比如CAS)代替锁来实现数据在并发访问中的一致性.应用于:操作系统和JVM中实现线程/进 ...

  2. 多线程-并发编程(7)-生产者消费者模式及非阻塞队列与阻塞队列实现

    生产者消费者模式是一个十分经典的多线程协作模式 弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻 存在3个元素 1.生产者(类比厨师) 2.生产者的生产产品(类比美食) 3.消费者(类比吃货) ...

  3. java多线程 --ConcurrentLinkedQueue 非阻塞 线程安全队列

    ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部:当我们获取一个元素时,它会返回队列头 ...

  4. java 注解_怎样理解 Java 注解和运用注解编程?

    怎样理解 Java 注解和运用注解编程? 注解和使用 先来看下概念首先从注释来看: 注释:给代码添加说明和解释,注释帮助开发人员理解程序.(Comment)说白点就是注释是给人看的. 注解:给代码添加 ...

  5. 深圳java培训:怎样理解 Java 注解和运用注解编程?

    深圳java培训:怎样理解 Java 注解和运用注解编程? 注解和使用 先来看下概念首先从注释来看: 注释:给代码添加说明和解释,注释帮助开发人员理解程序.(Comment)说白点就是注释是给人看的. ...

  6. java网络编程阻塞_Java网络编程由浅入深三 一文了解非阻塞通信的图文代码示例详解...

    本文详细介绍组成非阻塞通信的几大类:Buffer.Channel.Selector.SelectionKey 非阻塞通信的流程ServerSocketChannel通过open方法获取ServerSo ...

  7. 并发编程 – Concurrent 用户指南

    转载自 并发编程 – Concurrent 用户指南 1. java.util.concurrent – Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.c ...

  8. 15分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行,太实用了!

    作者:Martin cnblogs.com/mhq-martin/p/9035640.html 基本概念 1 进程和线程 进程(Process): 是Windows系统中的一个基本概念,它包含着一个运 ...

  9. 15分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行

    基本概念 1 进程和线程 进程(Process): 是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程 ...

  10. 进程线程、同步异步、阻塞非阻塞、并发并行、多线程

    一: 进程和线程 1: 进程(Process) 是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程.线 ...

最新文章

  1. quasar_Quasar和Akka –比较
  2. linux安卓主线程同步,Android解决:使用多线程和Handler同步更新UI
  3. ITK:处理矢量图像的N个分量
  4. 左值、右值、左值引用、右值引用
  5. 图像连通域检测的2路算法Code
  6. python可以开发驱动吗_Python机器学习实践:测试驱动的开发方法
  7. 11下滑半个屏幕_努比亚发布手表手机:柔性屏幕,体积感人
  8. 深度优先搜索——选数(洛谷 P1036)
  9. 这个 DNS 新漏洞可导致大规模的 DDoS 攻击活动
  10. java如何让cpu过负荷_服务器开发过载问题如何解决
  11. 咪咕:笔试题(20190916)
  12. NRC词典应用实例——英文文本情感分析
  13. 蓝桥杯单片机学习之数码管
  14. 广域网的应用场景是什么?
  15. 内存取证工具Volatility学习
  16. 超详细的Mysql安装教程
  17. 论文精度 —— 2018 CVPR《Generative Image Inpainting with Contextual Attention》
  18. 站长在线零基础Python完全自学教程20:在Python中使用正则表达式完全解读
  19. BeanFactory和ApplicationContext接口的联系和区别
  20. linux哪个系统好

热门文章

  1. r语言 小树转化百分数_魅力语言小课堂|绕口令《说日》
  2. AspectJ中5种类型的增强注解有什么区别?
  3. chainmaker-go-sdk get cert hash failed, get cert hash failed, send QUERY_SYSTEM_CONTRACT failed
  4. FISCO BCOS rpc端口、channel端口、p2p端口 怎么用是什么
  5. 支持乱序执行的RAFT协议 ppt
  6. java并发编程(8)-- 线程 阻塞队列 生产者消费者 lock synchronized
  7. 计算机硬盘存绝密,教您创建自己的绝密磁盘
  8. 数学建模第七章 数理统计
  9. 记飞机大战小游戏1.0
  10. java web文件拖拽上传文件_Java实现拖拽文件上传dropzone.js的简单使用示例代码