1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue

ArrayBlockingQueue, LinkedBlockingQueue 继承自 BlockingQueue, 他们的特点就是 Blocking, Blocking 特有的方法就是 take() 和 put(), 这两个方法是阻塞方法, 每当队列容量满的时候, put() 方法就会进入wait, 直到队列空出来, 而每当队列为空时, take() 就会进入等待, 直到队列有元素可以 take()

ArrayBlockingQueue, LinkedBlockingQueue 区别在于 ArrayBlockingQueue 必须指定容量, 且可以指定 fair 变量, 如果 fair 为 true, 则会保持 take() 或者 put() 操作时线程的 block 顺序, 先 block 的线程先 take() 或 put(), fair 又内部变量 ReentrantLock 保证

ConcurrentLinkedQueue 通过 CAS 操作实现了无锁的 poll() 和 offer(), 他的容量是动态的, 由于无锁, 所以在 poll() 或者 offer() 的时候 head 与 tail 可能会改变, 所以它会持续的判断 head 与 tail 是否改变来保证操作正确性, 如果改变, 则会重新选择 head 与 tail. 而由于无锁的特性, 他的元素更新与 size 变量更新无法做到原子 (实际上它没有 size 变量), 所以他的 size() 是通过遍历 queue 来获得的, 在效率上是 O(n), 而且无法保证准确性, 因为遍历的时候有可能 queue size 发生了改变.

RingBuffer 是 Distruptor 中的一个用来替代 ArrayBlockingQueue 的队列, 它的思想在于长度可控, 且无锁, 只有在 blocking 的时候(没有数据的时候出队, 数据满的时候入队)会自旋. 实现原理是使用一个环形array, 生产者作为 tail, 消费者作为 head, 每生产一次 tail atomic++, 每消费一次 head atomic++, tail 不能超过 head 一圈(array size, 即队列满时 blocking), tail 不能超过自己tail一圈(即不能覆盖未被消费的值), head 不能超过 tail (即无可消费任务时 blocking), head 不能取到空值(取到空值时 blocking). blocking 使用一个 while 自旋来完成, 那么只要生产者消费者的速度相当时, 即可通过 atomicInteger(cas) 保证无锁, 而如果你需要在 blocking 的时候立即返回, 则 while 自旋都可以不需要. 相比于 ArrayBlockingQueue, 它可以绝大部分时间无锁, blocking 自旋, 相比于 concurrentLinkedQueue, 他又能做到长度限制. 代码如下:

public class RingBuffer<T> implements Serializable {

    /**
*
*/
private static final long serialVersionUID = 6976960108708949038L; private volatile AtomicInteger head; private volatile AtomicInteger tail; private int length; final T EMPTY = null; private volatile T[] queue; public RingBuffer(Class<T> type, int length){
this.head = new AtomicInteger(0);
this.tail = new AtomicInteger(0);
this.length = length == 0 ? 2 << 16 : length; // 默认2^16
this.queue = (T[]) Array.newInstance(type, this.length);
} public void enQueue(T t){
if(t == null) t= (T) new Object();
// 阻塞 -- 避免多生成者循环生产同一个节点
while(this.getTail() - this.getHead() >= this.length);
int ctail = this.tail.getAndIncrement();
while(this.queue[this.getTail(ctail)] != EMPTY); // 自旋
this.queue[this.getTail(ctail)] = t;
} public T deQueue(){
T t = null;
// 阻塞 -- 避免多消费者循环消费同一个节点
while(this.head.get() >= this.tail.get());
int chead = this.head.getAndIncrement();
while(this.queue[this.getHead(chead)] == EMPTY); // 自旋
t = this.queue[this.getHead(chead)];
this.queue[this.getHead(chead)] = EMPTY;
return t;
} public int getHead(int index){
return index & (this.length - 1);
} public int getTail(int index) {
return index & (this.length - 1);
} public int getHead() {
return head.get() & (this.length - 1);
} public int getTail() {
return tail.get() & (this.length - 1);
} public T[] getQueue() {
return queue;
} public int getLength() {
return length;
} public void setLength(int length) {
this.length = length;
} }

ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, RingBuffer的更多相关文章

  1. 高并发第十三弹:J.U.C 队列 SynchronousQueue.ArrayBlockingQueue.LinkedBlockingQueue.LinkedTransferQueue

    因为下一节会说线程池,要用线程池 那么线程池有个很重要的参数 就是Queue的选择 常用的队列其实就两种: 先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能.从某种程度上来说这种 ...

  2. LinkedBlockingQueue与ArrayBlockingQueue

    阻塞队列与普通的队列(LinkedList/ArrayList)相比,支持在向队列中添加元素时,队列的长度已满阻塞当前添加线程,直到队列未满或者等待超时:从队列中获取元素时,队列中元素为空 ,会将获取 ...

  3. LinkedBlockingQueue 和 ConcurrentLinkedQueue的区别

    1. 简单的开篇 LinkedBlockingQueue 和 ConcurrentLinkedQueue 是 Java 高并发场景中最常使用的队列.尽管这两个队列经常被用作并发场景的数据结构,但它们之 ...

  4. Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

    1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...

  5. 五种并发包总结ConcurrentHashMap CopyOnWriteArrayList ArrayblockingQueue

    五种并发包总结 1.常用的五种并发包 ConcurrentHashMap CopyOnWriteArrayList CopyOnWriteArraySet ArrayBlockingQueue Lin ...

  6. java多线程系类:JUC集合:01之框架

    概要 之前,在"Java 集合系列目录(Category)"中,讲解了Java集合包中的各个类.接下来,将展开对JUC包中的集合进行学习.在学习之前,先温习一下"Java ...

  7. Java多线程系列--“JUC集合”01之 框架

    概要 之前,在"Java 集合系列目录(Category)"中,讲解了Java集合包中的各个类.接下来,将展开对JUC包中的集合进行学习.在学习之前,先温习一下"Java ...

  8. Java集合容器简介

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

  9. Java队列集合的性能测试

    同时开10个线程存入和取出100万的数据,结论如下: DoubleBufferedQueue < ConcurrentLinkedQueue < ArrayBlockingQueue &l ...

随机推荐

  1. AngularJS过滤器filter入门

    在开发中,经常会遇到这样的场景 如用户的性别分为“男”和“女”,在数据库中保存的值为1和0,用户在查看自己的性别时后端返回的值自然是1或0,前端要转换为“男”或“女”再显示出来: 如我要换个羽毛球拍, ...

  2. 命令:tr

    参考资料:https://www.thegeekstuff.com/2012/12/linux-tr-command/ 简介 tr命令用于转换.删除或者去除重复字符.它从STDIN中读取数据并且将其写 ...

  3. android studio svn 创建分支

    创建分支或标签 从哪里复制 工作副本 用这个变体去创建分支,并带着当地的改变.通常,服务项将被 添加带历史 , 不仅仅只有目标目录. 每个不同于根的版本文件 ,将被指定的复制.它推荐 去更新 工作副本 ...

  4. UOJ.179.线性规划(单纯形)

    题目链接 这写得还不错:http://www.cnblogs.com/zzqsblog/p/5457091.html 引入基变量\(x_{i+n}\),将约束\(\sum_{i=1}^m a_{ij} ...

  5. COJ1013 WZJ的数据结构(十三)

    WZJ的数据结构(十三) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个节点的有根树(根节点为1),每个节点有权 ...

  6. Linux学习笔记09—Sqlyog链接mysql配置

    第一步打开Linux命令窗口,进入超级用户.命令:[test@localhost ~]$ suPassword:输入超级用户密码第二步启动Mysql服务命令:[root@localhost test] ...

  7. 【原】使用Eclipse远程Debug测试环境

    [环境参数] Eclipse:Version: Mars.2 Release (4.5.2) Linux:centOS 6.5 [简述] Java自身支持调试功能,并提供了一个简单的调试工具--JDB ...

  8. [原创]浅谈移动App安全测试

    [原创]浅谈移动App安全测试 移动互联网很火,就像当年互联网兴起一样,这几天和朋友在沟通交流,谈到一个话题,你们做金融App钱放在你们哪边安全不?会不会你们做的移动App不安全,让人盗了里面的资金, ...

  9. STM32 F4 General-purpose Timers for Periodic Interrupts

    STM32 F4 General-purpose Timers for Periodic Interrupts

  10. bitnami redmine配置全过程

    常见问题: 我在自己的机器上面配置完毕以后,移植到另外一台机器上面,登陆页面总是在检查network,并且最后网络加载失败,不论我是用桥接还是NAT方式连接.登陆系统以后,我尝试连接网络失败,尝试执行 ...