zoukankan      html  css  js  c++  java
  • java并发编程(二十五)----(JUC集合)LinkedBlockingDeque和ConcurrentLinkedDeque介绍

    Queue除了前面介绍的实现外,还有一种双向的Queue实现Deque。这种队列允许在队列头和尾部进行入队出队操作,因此在功能上比Queue显然要更复杂。

    LinkedBlockingDeque

    我们来看一下该类中的成员变量:

    public class LinkedBlockingDeque<E>
            extends AbstractQueue<E>
            implements BlockingDeque<E>,  java.io.Serializable {
    
        private static final long serialVersionUID = -387911632671998426L;
    
        static final class Node<E> {    
            E item;
            Node<E> prev;
            Node<E> next;
            Node(E x) {
                item = x;
            }
        }  
        transient Node<E> first;
        transient Node<E> last;
        private transient int count;
        private final int capacity;
        final ReentrantLock lock = new ReentrantLock();
        private final Condition notEmpty = lock.newCondition();
        private final Condition notFull = lock.newCondition();
    
    }

    有一个内部类Node,该类用来标记queue的节点,capacity最大为Integer.MAX_VALUE。然后使用了独占锁和条件机制来保证线程安全和进行阻塞控制。从上面的结构上我们可以看出:

    1. 要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是final类型的。
    2. 既然是双向链表,每一个结点就需要前后两个引用,这样才能将所有元素串联起来,支持双向遍历。也即需要prev/next两个引用。
    3. 双向链表需要头尾同时操作,所以需要first/last两个节点,当然可以参考LinkedList那样采用一个节点的双向来完成,那样实现起来就稍微麻烦点。
    4. 既然要支持阻塞功能,就需要锁和条件变量来挂起线程。这里使用一个锁两个条件变量来完成此功能。

    上面对LinkedBlockingDeque的结构做了说明,那么原理就很清晰了,无非是用一个独占锁来保持线程安全,然后用Condition来做阻塞操作。双向链表的操作大家都很熟悉就不做过多解释。

    ConcurrentLinkedDeque

    ConcurrentLinkedDeque是JSR166y中新增的一个无界并发Deque实现,基于已链接节点的、任选范围的双端队列。在迭代时,队列保持弱一致性,但不会抛出ConcurrentModificationException异常。

    我们看一下类的成员变量:

    public class ConcurrentLinkedDeque<E>
            extends AbstractCollection<E>
            implements Deque<E>, java.io.Serializable {
    
        private transient volatile Node<E> head;
        private transient volatile Node<E> tail;
    
        private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
    
        @SuppressWarnings("unchecked")
        Node<E> prevTerminator() {
            return (Node<E>) PREV_TERMINATOR;
        }
    
        @SuppressWarnings("unchecked")
        Node<E> nextTerminator() {
            return (Node<E>) NEXT_TERMINATOR;
        }
    }

    我们看到成员变量里面有头节点和尾节点,然后是节点的引用PREV_TERMINATOR, NEXT_TERMINATOR,
    双向链表的结构都是一样的。ConcurrentLinkedDeque不是阻塞队列所以没有用到条件原语。我们在成员变量里面没有看到使用ReentrantLock,因为所有的操作都是使用原子操作,避免了使用独占锁造成性能问题。

  • 相关阅读:
    转:一道笔试题-将int型数组强制转换为char*,再求strlen,涉及大小端
    转:git windows中文 乱码问题解决汇总
    git教程1
    刘汝佳黑书 pku等oj题目
    C/C++ qsort()快速排序用法
    char s[]字串和char *s字串有什麼区别?
    c语言‘’ ,‘0’, “0” ,0之间的区别
    带符号的char类型取值范围为什么是-128——127
    c语言memset详解
    【线性规划与网络流24题】孤岛营救问题 分层图
  • 原文地址:https://www.cnblogs.com/rickiyang/p/11074245.html
Copyright © 2011-2022 走看看