美文网首页Android开发Android开发经验谈Android开发
深入理解并发类库中提供线程安全队列

深入理解并发类库中提供线程安全队列

作者: 遛狗的程序员 | 来源:发表于2018-08-10 22:25 被阅读7次

    问题:

    并发包中ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?

    知识点

    • Java并发类库中提供的各种各样的线程安全队列
    image
    • BlockingQueue提供了特定的等待性操作,获取(take)等待元素进队,或者插入(put)等待队列出现空位。

    源码:

     /**
         * Retrieves and removes the head of this queue, waiting if necessary
         * until an element becomes available.
         *
         * @return the head of this queue
         * @throws InterruptedException if interrupted while waiting
         */
        E take() throws InterruptedException;
    
     /**
         * Inserts the specified element into this queue, waiting if necessary
         * for space to become available.
         *
         * @param e the element to add
         * @throws InterruptedException if interrupted while waiting
         * @throws ClassCastException if the class of the specified element
         *         prevents it from being added to this queue
         * @throws NullPointerException if the specified element is null
         * @throws IllegalArgumentException if some property of the specified
         *         element prevents it from being added to this queue
         */
        void put(E e) throws InterruptedException;
    
    • ArrayBlockQueue是典型的有界队列,其内部是以final的数组保存数据,数组的大小就决定了队列的边界,所以我们在创建ArrayBlockingQueue时,都指定容量,如:
    /**
         * Creates an {@code ArrayBlockingQueue} with the given (fixed)
         * capacity and default access policy.
         *
         * @param capacity the capacity of this queue
         * @throws IllegalArgumentException if {@code capacity < 1}
         */
        public ArrayBlockingQueue(int capacity) {
            this(capacity, false);
        }
    
    
    • LinkedBlockingQueue,容易被误解为无边界,但其行为和内部代码都是基于有界的逻辑实现的,只不过如果我们没有在创建队列时就指定容量,那么其容量限制就自动设置Integer.MAX_VALUE,称为了无界队列。
     /**
         * Creates a {@code LinkedBlockingQueue} with a capacity of
         * {@link Integer#MAX_VALUE}.
         */
        public LinkedBlockingQueue() {
            this(Integer.MAX_VALUE);
        }
    
    • SynchronousQueue,这是一个非常奇葩的队列实现,每个删除操作都要等待插入操作,反之每个插入操作都要等待删除动作。那么这个队列的容量是多少呢?是1吗?其实不是的,其内部容量是0。
    • PriorityBlockingQueue是无边界的优先队列,虽然严格意义上讲,其大小总归是手系统资源影响。
    • DelayQueue和LinkedTransferQueue同样是无边界的队列。对于无边界的队列,有一个自然的结果,就是put操作永远也不会发生其他BlockingQueue的那种等待情况。

    回答问题:

    有时候我们把并发包下面的所有容器都习惯叫做并发容器,但是严格来讲,类似ConcurrentLinkedQueue这种“Concurrent”容器,才是真正代表并发。
    关于问题中它们的区别:

    • Concurrent类型基于lock-free,在常见的多线程访问场景,一般可以提供较高吞吐量。
    • 而LinkedBlockingQueue内部则是基于锁,并提供了BlockingQueue的等待性方法。
      不知道你有没有注意到,java.util.concurrent包提供的容器(Queue、List、Set)、Map,从命名上可以大概区分为Concurrent*、CopyOnWrite和Blocking等三类,同样是线程安全容器,可以简单认为:
    • Concurrent类型没有类似CopyOnWrite之类容器较重的修改开销。
    • 但是,凡是都是有代价的,Concurrent往往提供了较低的遍历一致性,你可以这样理解所谓的弱一致性,例如,当李勇迭代器遍历时,如果容器发生修改,迭代器仍然可以继续进行遍历。
    • 与弱一致性对应的,就是我介绍过的同步容器常见的行为“fail-fast",也就是检测到容器在遍历过程中发生了修改,则抛出ConcurrentModificationException,不再继续遍历。
    • 弱一致性的另外一个体现是,size等操作准确性是有线的,未必是100%准确。
    • 与此同时,读取的性能具有一定的不确定性。

    参考:

    • 队列中部分源码
    • 极客时间APP核心技术第20讲| 并发包中ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?

    声明:此为原创,转载请联系作者


    作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。

    qrcode_for_gh_1ba0785324d6_430.jpg

    当然喜爱技术,乐于分享的你也可以可以添加作者微信号:

    WXCD.jpeg

    相关文章

      网友评论

        本文标题:深入理解并发类库中提供线程安全队列

        本文链接:https://www.haomeiwen.com/subject/orfrbftx.html