zoukankan      html  css  js  c++  java
  • java中的线程安全队列

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

    使用阻塞算法的队列可以用一个锁(出入队列用同一把锁),或两个锁(入队和出队用不同的锁),非阻塞的实现方式则可以用循环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来保证生产和消费的同步;

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

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

    不同:

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

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

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

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

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

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

    而ArrayBlockingQueue内部维护了一个数组

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

     3、构造时候的区别

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

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

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

    4、执行clear()方法

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

    5、统计元素的个数

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

     

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


    阻塞队列的实现

    https://segmentfault.com/a/1190000000373535

    参考:

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

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

  • 相关阅读:
    hdu 4739 Zhuge Liang's Mines DFS
    Uva 12304
    三角形的心
    最小路径覆盖的理解
    Codeforces Round #192 (Div. 2)
    Uva 11796 Dog Distance
    laravel框架session使用教程
    php session跨页面传递 session值丢失问题
    PHP 5.4中的traits特性
    PHP5.3 goto操作符介绍
  • 原文地址:https://www.cnblogs.com/dingpeng9055/p/11351168.html
Copyright © 2011-2022 走看看