java并发编程(二十五)----(JUC集合)LinkedBlockingDeque和ConcurrentLinkedDeque介绍
2017-03-02 23:45
363 查看
Queue除了前面介绍的实现外,还有一种双向的Queue实现Deque。这种队列允许在队列头和尾部进行入队出队操作,因此在功能上比Queue显然要更复杂。
有一个内部类Node,该类用来标记queue的节点,capacity最大为Integer.MAX_VALUE。然后使用了独占锁和条件机制来保证线程安全和进行阻塞控制。从上面的结构上我们可以看出:
要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是final类型的。
既然是双向链表,每一个结点就需要前后两个引用,这样才能将所有元素串联起来,支持双向遍历。也即需要prev/next两个引用。
双向链表需要头尾同时操作,所以需要first/last两个节点,当然可以参考LinkedList那样采用一个节点的双向来完成,那样实现起来就稍微麻烦点。
既然要支持阻塞功能,就需要锁和条件变量来挂起线程。这里使用一个锁两个条件变量来完成此功能。
上面对LinkedBlockingDeque的结构做了说明,那么原理就很清晰了,无非是用一个独占锁来保持线程安全,然后用Condition来做阻塞操作。双向链表的操作大家都很熟悉就不做过多解释。
我们看一下类的成员变量:
我们看到成员变量里面有头节点和尾节点,然后是节点的引用PREV_TERMINATOR, NEXT_TERMINATOR,
双向链表的结构都是一样的。ConcurrentLinkedDeque不是阻塞队列所以没有用到条件原语。我们在成员变量里面没有看到使用ReentrantLock,因为所有的操作都是使用原子操作,避免了使用独占锁造成性能问题。
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。然后使用了独占锁和条件机制来保证线程安全和进行阻塞控制。从上面的结构上我们可以看出:
要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是final类型的。
既然是双向链表,每一个结点就需要前后两个引用,这样才能将所有元素串联起来,支持双向遍历。也即需要prev/next两个引用。
双向链表需要头尾同时操作,所以需要first/last两个节点,当然可以参考LinkedList那样采用一个节点的双向来完成,那样实现起来就稍微麻烦点。
既然要支持阻塞功能,就需要锁和条件变量来挂起线程。这里使用一个锁两个条件变量来完成此功能。
上面对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,因为所有的操作都是使用原子操作,避免了使用独占锁造成性能问题。
相关文章推荐
- java并发编程(二十四)----(JUC集合)ArrayBlockingQueue和LinkedBlockingQueue介绍
- Java多线程系列--“JUC集合”09之 LinkedBlockingDeque
- Java多线程系列--【JUC集合09】- LinkedBlockingDeque
- Java多线程系列--“JUC集合”09之 LinkedBlockingDeque
- Java集合类(二十一)JUC中的集合--LinkedBlockingDeque
- Java多线程系列--“JUC集合”09之 LinkedBlockingDeque
- Java多线程系列--“JUC集合”09之 LinkedBlockingDeque
- Java多线程系列--“JUC集合”09之 LinkedBlockingDeque
- JUC集合-09之 LinkedBlockingDeque
- Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueu
- 05.JUC 集合 - LinkedBlockingQueue
- Java常见集合框架(十八): Deque之Deque、BlockingDeque、LinkedBlockingDeque、ArrayDeque
- Java多线程--并发中集合的使用之ConcurrentLinkedDeque
- Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue
- JUC源码分析21-队列-LinkedBlockingDeque
- Java多线程系列--“JUC集合”08之 LinkedBlockingQueue
- java.util.concurrent系列之--LinkedBlockingDeque
- JUC集合-10之 ConcurrentLinkedQueue
- Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueue
- Java之集合(十九)LinkedBlockingDeque