java中的线程安全队列

摘要:
有时需要使用线程安全队列。使用阻塞算法的队列可以使用锁(相同的锁用于入站和出站队列)。非阻塞队列ConcurrentLinkedQueue ConcurrentLinked queue由头部节点和尾部节点组成。两个阻塞队列JDK7是线程安全的,它使用优先级队列提供了七个阻塞队列和三个无边界阻塞队列。ー 由链表结构组成的无限阻塞队列。ー 由链表结构组成的双向阻塞队列。

在并发编程中,有时候需要使用线程安全的队列,如果要实现一个线程安全的队列有两种实现方式:阻塞算法、非阻塞算法。

使用阻塞算法的队列可以用一个锁(出入队列用同一把锁),或两个锁(入队和出队用不同的锁),非阻塞的实现方式则可以用循环CAS的方式实现。

一 非阻塞方式实现线程安全的队列

ConcurrentLinkedQueue

 ConcurrentLinkedQueue由head节点和tail节点组成,每个节点node由节点元素item和指向下一个节点next的引用组成。当我们增加一个元素时,它会添加到队列的末尾,当我们取一个元素时,它会返回一个队列头部的元素。

虽然ConcurrentLinkedQueue的性能很好,但是在调用size()方法的时候,会遍历一遍集合,对性能损害较大,执行很慢,因此应该尽量的减少使用这个方法,如果判断是否为空,最好用isEmpty()方法

 ConcurrentLinkedQueue不允许插入null元素,会抛出空指针异常。

 ConcurrentLinkedQueue是无界的,所以使用时,一定要注意内存溢出的问题。即对并发不是很大中等的情况下使用,不然占用内存过多或者溢出,对程序的性能影响很大,甚至是致命的。 

二 阻塞方式实现线程安全的对列

JDK7提供了7个阻塞队列,如下。
口 ArrayBlockingqueue:ー个由数组结构组成的有界阻塞队列。
口 LinkedBlockingqueue:一个由链表结构组成的有界阻塞队列。
口 PriorityBlockingqueue:一个支持优先级排序的无界阻塞队列。
口 Delayqueue:ー个使用优先级队列实现的无界阻塞队列。
口 Synchronousqueue:一个不存储元素的阻塞队列。
口 Linkedtransferqueue:ー个由链表结构组成的无界阻塞队列。
口 LinkedblockingDeque:ー个由链表结构组成的双向阻塞队列。

ArrayBlockingQueue 

LinkedBlockingQueue 


 ConcurrentLinkedQueue、ArrayBlockingQueue、LinkedBlockingQueue 区别及使用场景

ArrayBlockingQueue extends AbstractQueue implements BlockingQueue 
LinkedBlockingQueue extends AbstractQueue implements BlockingQueue
ConcurrentLinkedQueue extends AbstractQueue implements Queue

ConcurrentLinkedQueue基于CAS的无锁技术,不需要在每个操作时使用锁,所以扩展性表现要更加优异,在常见的多线程访问场景,一般可以提供较高吞吐量。

LinkedBlockingQueue内部则是基于锁,并提供了BlockingQueue的等待性方法。

ArrayBlockingQueue是初始容量固定的阻塞队列,我们可以用来作为数据库模块成功竞拍的队列,比如有10个商品,那么我们就设定一个10大小的数组队列。

ConcurrentLinkedQueue使用的是CAS原语无锁队列实现,是一个异步队列入队的速度很快出队进行了加锁,性能稍慢。

LinkedBlockingQueue也是阻塞的队列,入队和出队都用了加锁,当队空的时候线程会暂时阻塞。


 LinkedBlockingQueue与ArrayBlockingQueue的异同

相同:

1、LinkedBlockingQueue和ArrayBlockingQueue都实现了BlockingQueue接口;

2、LinkedBlockingQueue和ArrayBlockingQueue都是可阻塞的队列 

  内部都是使用ReentrantLock和Condition来保证生产和消费的同步;

  当队列为空,消费者线程被阻塞;当队列装满,生产者线程被阻塞;

java中的线程安全队列第1张

使用Condition的方法来同步和通信:await()和signal()

不同:

1、由上图可以看出,他们的锁机制不同

  LinkedBlockingQueue中的锁是分离的,生产者的锁PutLock,消费者的锁takeLock

  而ArrayBlockingQueue生产者和消费者使用的是同一把锁;

2、他们的底层实现机制也不同

  LinkedBlockingQueue内部维护的是一个链表结构

java中的线程安全队列第2张

在生产和消费的时候,需要创建Node对象进行插入或移除,大批量数据的系统中,其对于GC的压力会比较大

而ArrayBlockingQueue内部维护了一个数组

java中的线程安全队列第3张

在生产和消费的时候,是直接将枚举对象插入或移除的,不会产生或销毁任何额外的对象实例

 3、构造时候的区别

  LinkedBlockingQueue有默认的容量大小为:Integer.MAX_VALUE,当然也可以传入指定的容量大小

java中的线程安全队列第4张

ArrayBlockingQueue在初始化的时候,必须传入一个容量大小的值

  看其提供的构造方法就能知道

java中的线程安全队列第5张

4、执行clear()方法

  LinkedBlockingQueue执行clear方法时,会加上两把锁

java中的线程安全队列第6张

5、统计元素的个数

 LinkedBlockingQueue中使用了一个AtomicInteger对象来统计元素的个数

 java中的线程安全队列第7张

 ArrayBlockingQueue则使用int类型来统计元素


阻塞队列的实现

https://segmentfault.com/a/1190000000373535

参考:

https://www.jb51.net/article/90899.htm

https://blog.csdn.net/jameshadoop/article/details/52729796

免责声明:文章转载自《java中的线程安全队列》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【高速接口-RapidIO】6、Xilinx RapidIO核仿真与包时序分析外部程序通过COM启动AutoCAD时RPC_E_CALL_REJECTED的问题解决办法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

阻塞队列和死锁

BlockingQueue        BlockingQueue是并发容器的一种,在J.U.C的包路径下,是线程安全的一种实现,是基于阻塞队列的,该接口提供了相对于Queue的新的put()和take()操作。put()添加元素时,当阻塞队列满的情况下会阻塞下来,当有空间时才能进行添加操作,添加到队列尾部;take()删除元素时,当队列为空时,也会阻塞...

CSS3:选择器整理,附css的骚操作,实现表单验证、ios切换按钮……

CSS的选择器很多,整理一下,方便熟悉使用。 基础的标签选择器、#id、.class、*通配符选择器这些常见的就不讲了。 主要记录一些不常用的且实用的,更多参考w3school手册 条件选择器: :has 包含指定的元素 :is   指定条件的元素 :not   非指定条件的元素 :where   指定条件的元素 :scope 指定元素作为参考点 :an...

STL之六:map/multimap用法详解

转载于:http://blog.csdn.net/longshengguoji/article/details/8547007 map/multimap     使用map/multimap之前要加入头文件#include<map>,map和multimap将key/value当作元素,进行管理。它们可根据key的排序准则自动将元素排序。mul...

linux 2.6 互斥锁的实现-源码分析

http://blog.csdn.net/tq02h2a/article/details/4317211 看了看linux 2.6 kernel的源码,下面结合代码来分析一下在X86体系结构下,互斥锁的实现原理。 代码分析 1. 首先介绍一下互斥锁所使用的数据结构:struct mutex { 引用计数器 1: 所可以利用。  小于等于0:该锁已被获取,需...

python——js 或Jquery操作定位元素

原文:https://www.cnblogs.com/dangkai/p/9948573.html 属性过滤常用javascript后去DOM对象 id是定位到的是单个element元素对象,其它的都是elements返回的是list对象 1.通过id获取 document.getElementById(“id”) 2.通过name获取  documen...

RabbitMQ---7、常见参数含义

简介 本节主要讨论队列声明的各个参数 queueDeclare(String queue, boolean durable, boolean exclusive, Map<String, Object> arguments); queue: 队列名称 durabl...