高并发编程之 ConcurrentLinkedDeque 讲解

一、ConcurrentLinkedDeque 介绍
ConcurrentLinkedDeque 是双向链表结构无界并发队列。从 JDK 7 开始加入到 J.U.C 的行列中。使用 CAS 实现并发安全,与 ConcurrentLinkedQueue 的区别是该阻塞队列同时支持 FIFO 和 FILO 两种操作方式,即可以从队列的头和尾同时操作 (插入 / 删除)。适合 “多生产,多消费” 的场景。内存一致性遵循对 ConcurrentLinkedDeque 的插入操作先行发生于 (happen-before) 访问或移除操作。相较于 ConcurrentLinkedQueue,ConcurrentLinkedDeque 由于是双端队列,所以在操作和概念上会更加复杂。
注意:size 方法不是一个准确的操作

二、ConcurrentLinkedDeque 的一些方法介绍
1、add (E e):在此 deque 的尾部插入指定的元素,返回值为 Boolean。
2、addFirst (E e):在此 deque 前面插入指定的元素。
3、addLast (E e):在此 deque 的末尾插入指定的元素。
4、clear ():从这个 deque 中删除所有的元素。
5、contains (Object o):返回 true 如果这个 deque 包含至少一个元素 e ,返回值为 Boolean。
6、descendingIterator ():以相反的顺序返回此 deque 中的元素的迭代器,返回值为 Iterator。
7、element ():检索但不删除由此 deque 表示的队列的头部(换句话说,该 deque 的第一个元素)。
8、getFirst ():检索,但不删除,这个 deque 的第一个元素。
9、getLast ():检索,但不删除,这个 deque 的最后一个元素。
10、isEmpty ():如果此集合不包含元素,则返回 true 。
11、iterator ():以正确的顺序返回此 deque 中的元素的迭代器,返回值为 Iterator 。
12、offer (E e):在此 deque 的尾部插入指定的元素,返回值为 boolean。
13、offerFirst (E e):在此 deque 前面插入指定的元素,返回值为 boolean。
14、offerLast (E e):在此 deque 的末尾插入指定的元素,返回值为 boolean。
15、peek ():检索但不删除由此 deque 表示的队列的头(换句话说,该 deque 的第一个元素),如果此 deque 为空,则返回 null 。
16、peekFirst ():检索但不删除此 deque 的第一个元素,如果此 deque 为空,则返回 null 。
17、peekLast ():检索但不删除此 deque 的最后一个元素,如果此 deque 为空,则返回 null 。
18、poll ():检索并删除由此 deque 表示的队列的头部(换句话说,该 deque 的第一个元素),如果此 deque 为空,则返回 null 。
19、pollFirst ():检索并删除此 deque 的第一个元素,如果此 deque 为空,则返回 null 。
20、pollLast ():检索并删除此 deque 的最后一个元素,如果此 deque 为空,则返回 null 。
21、pop ():从这个 deque 表示的堆栈中弹出一个元素。
22、push (E e):将元素推送到由此 deque 代表的堆栈(换句话说,在该 deque 的头部),如果可以立即执行,而不违反容量限制,则抛出 IllegalStateException 如果当前没有可用空间)。
23、remove ():检索并删除由此 deque 表示的队列的头(换句话说,该 deque 的第一个元素)。
24、remove (Object o):删除第一个元素 e ,使 o.equals (e) ,如果这样一个元素存在于这个 deque,返回值为 boolean。
25、removeFirst ():检索并删除此 deque 的第一个元素。
26、removeFirstOccurrence (Object o):删除第一个元素 e ,使 o.equals (e) ,如果这样一个元素存在于这个 deque,返回值为 boolean。
27、removeLast ():检索并删除此 deque 的最后一个元素。
28、size ():返回此 deque 中的元素数。

三、Java 代码示例

package chapter3.concurrentlinkeddeque;

import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * @author czd
 */
public class ConcurrentLinkedDequeTest {
    public static void main(String[] args) {
        /**
         * 构造方法
         * ConcurrentLinkedDeque():
         *                构造一个空的德克。
         * ConcurrentLinkedDeque(Collection<? extends E> c):
         *               构造最初包含给定集合的元素的deque,以集合的迭代器的遍历顺序添加。
         */

        /**
         * 	1、add(E e):在此deque的尾部插入指定的元素。
         *
         * 	2、iterator():以正确的顺序返回此deque中的元素的迭代器。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque = new ConcurrentLinkedDeque<>();
        Boolean addBoolean = concurrentLinkedDeque.add(5);
        System.out.println("是否插入deque尾部成功?" + addBoolean);

        Iterator<Integer> iterator = concurrentLinkedDeque.iterator();
        while (iterator.hasNext()){
            System.out.println("iterator的结果:" + iterator.next());
        }


        /**
         * 3、addFirst(E e):在此deque前面插入指定的元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque1 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque1.addFirst(1);
        concurrentLinkedDeque1.addFirst(2);
        concurrentLinkedDeque1.addFirst(3);

        Iterator<Integer> iterator1 = concurrentLinkedDeque1.iterator();
        while (iterator1.hasNext()){
            System.out.println("iterator的结果:" + iterator1.next());
        }

        /**
         * 4、addLast(E e):在此deque的末尾插入指定的元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque2 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque2.addLast(7);
        concurrentLinkedDeque2.addLast(8);
        concurrentLinkedDeque2.addLast(9);

        System.out.println("=================");
        Iterator<Integer> iterator2 = concurrentLinkedDeque2.iterator();
        while (iterator2.hasNext()){
            System.out.println("iterator的结果:" + iterator2.next());
        }

        /**
         * 5、contains(Object o):返回 true如果这个deque包含至少一个元素 e ,返回值为Boolean。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque3 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque3.add(7);
        concurrentLinkedDeque3.add(8);
        concurrentLinkedDeque3.add(9);
        Boolean containsBoolean = concurrentLinkedDeque3.contains(8);
        System.out.println("concurrentLinkedDeque3是否包含8: " + containsBoolean);

        /**
         * 6、getFirst():检索,但不删除,这个deque的第一个元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque4 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque4.add(1);
        concurrentLinkedDeque4.add(2);
        concurrentLinkedDeque4.add(3);
        Integer getFirstResult = concurrentLinkedDeque4.getFirst();
        System.out.println("deque的第一个元素:" + getFirstResult);

        /**
         * 7、getLast():检索,但不删除,这个deque的最后一个元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque5 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque5.add(4);
        concurrentLinkedDeque5.add(5);
        concurrentLinkedDeque5.add(6);
        Integer getLast = concurrentLinkedDeque5.getLast();
        System.out.println("deque的最后一个元素:" + getLast);

        /**
         * 8、isEmpty():如果此集合不包含元素,则返回 true 。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque6 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque6.add(7);
        concurrentLinkedDeque6.add(8);
        concurrentLinkedDeque6.add(9);
        Boolean isEmptyBoolean = concurrentLinkedDeque5.isEmpty();
        System.out.println("deque是否为空:" + isEmptyBoolean);

        /**
         * 9、offer(E e):在此deque的尾部插入指定的元素,返回值为Boolean。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque7 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque7.offer(7);
        concurrentLinkedDeque7.offer(8);
        concurrentLinkedDeque7.offer(9);
        System.out.println("=================");
        Iterator<Integer> iterator3 = concurrentLinkedDeque7.iterator();
        while (iterator3.hasNext()){
            System.out.println("iterator的结果:" + iterator3.next());
        }

        /**
         * 10、offerFirst(E e):在此deque前面插入指定的元素,返回值为Boolean。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque8 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque8.offerFirst(7);
        concurrentLinkedDeque8.offerFirst(8);
        concurrentLinkedDeque8.offerFirst(9);
        System.out.println("=================");
        Iterator<Integer> iterator4 = concurrentLinkedDeque8.iterator();
        while (iterator4.hasNext()){
            System.out.println("iterator的结果:" + iterator4.next());
        }

        /**
         * 11、offerLast(E e):在此deque的末尾插入指定的元素,返回值为Boolean。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque9 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque9.offerLast(7);
        concurrentLinkedDeque9.offerLast(8);
        concurrentLinkedDeque9.offerLast(9);
        System.out.println("=================");
        Iterator<Integer> iterator5 = concurrentLinkedDeque9.iterator();
        while (iterator5.hasNext()){
            System.out.println("iterator的结果:" + iterator5.next());
        }

        /**
         * 12、peek():检索但不删除由此deque表示的队列的头(换句话说,该deque的第一个元素),
         *            如果此deque为空,则返回 null 。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque10 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque10.offer(7);
        concurrentLinkedDeque10.offer(8);
        concurrentLinkedDeque10.offer(9);
        System.out.println("队列的头: " + concurrentLinkedDeque10.peek());

        /**
         * 13、peekFirst():检索但不删除此deque的第一个元素,如果此deque为空,则返回 null 。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque11 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque11.offer(4);
        concurrentLinkedDeque11.offer(5);
        concurrentLinkedDeque11.offer(6);
        System.out.println("队列的头: " + concurrentLinkedDeque11.peekFirst());

        /**
         * 14、peekLast():检索但不删除此deque的最后一个元素,如果此deque为空,则返回 null
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque12 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque12.offer(1);
        concurrentLinkedDeque12.offer(2);
        concurrentLinkedDeque12.offer(3);
        System.out.println("队列的最后一个元素: " + concurrentLinkedDeque12.peekLast());

        /**
         * 15、	poll():检索并删除由此deque表示的队列的头部(换句话说,该deque的第一个元素),
         *            如果此deque为空,则返回 null 。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque13 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque13.addFirst(1);
        concurrentLinkedDeque13.addFirst(2);
        concurrentLinkedDeque13.addFirst(3);
        Integer addFirstResult = concurrentLinkedDeque13.poll();
        System.out.println("addFirstResult: " + addFirstResult);
        System.out.println("concurrentLinkedDeque13是否还包含3?" + concurrentLinkedDeque13.contains(3));

        /**
         * 16、pollFirst():检索并删除此deque的第一个元素,如果此deque为空,则返回 null 。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque14 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque14.addFirst(4);
        concurrentLinkedDeque14.addFirst(5);
        concurrentLinkedDeque14.addFirst(6);
        Integer pollFirstResult = concurrentLinkedDeque14.pollFirst();
        System.out.println("pollFirstResult: " + pollFirstResult);
        System.out.println("concurrentLinkedDeque14是否还包含6?" + concurrentLinkedDeque14.contains(6));

        /**
         * 17、pollLast():检索并删除此deque的最后一个元素,如果此deque为空,则返回 null 。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque15 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque15.addFirst(7);
        concurrentLinkedDeque15.addFirst(8);
        concurrentLinkedDeque15.addFirst(9);
        Integer pollLast = concurrentLinkedDeque15.pollLast();
        System.out.println("pollLast: " + pollLast);
        System.out.println("concurrentLinkedDeque15是否还包含7?" + concurrentLinkedDeque15.contains(7));

        /**
         * 18、pop():从这个deque表示的堆栈中弹出一个元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque16 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque16.addLast(7);
        concurrentLinkedDeque16.addLast(8);
        concurrentLinkedDeque16.addLast(9);
        Integer popResult = concurrentLinkedDeque16.pop();
        System.out.println("popResult: " + popResult);
        System.out.println("concurrentLinkedDeque16是否还包含7?" + concurrentLinkedDeque16.contains(7));

        /**
         * 19、push(E e):将元素推送到由此deque代表的堆栈(换句话说,在该deque的头部),
         *               如果可以立即执行,而不违反容量限制,
         *               则抛出 IllegalStateException如果当前没有可用空间)。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque17 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque17.push(7);
        concurrentLinkedDeque17.push(8);
        concurrentLinkedDeque17.push(9);
        System.out.println("=================");
        Iterator<Integer> iterator6 = concurrentLinkedDeque17.iterator();
        while (iterator6.hasNext()){
            System.out.println("iterator的结果:" + iterator6.next());
        }

        /**
         * 20、remove():检索并删除由此deque表示的队列的头(换句话说,该deque的第一个元素)。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque18 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque18.push(1);
        concurrentLinkedDeque18.push(2);
        concurrentLinkedDeque18.push(3);
        Integer removeResult = concurrentLinkedDeque18.remove();
        System.out.println("removeResult: " + removeResult);
        System.out.println("concurrentLinkedDeque18是否还包含3?" + concurrentLinkedDeque18.contains(3));

        /**
         * 21、remove(Object o):删除第一个元素 e ,如果这样一个元素存在于这个deque,返回值为Boolean。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque19 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque19.push(4);
        concurrentLinkedDeque19.push(5);
        concurrentLinkedDeque19.push(6);
        Boolean removeBoolean = concurrentLinkedDeque19.remove(5);
        System.out.println("是否移除5成功?" + removeBoolean);
        System.out.println("concurrentLinkedDeque19是否还包含3?" + concurrentLinkedDeque19.contains(5));


        /**
         * 22、removeFirst():检索并删除此deque的第一个元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque20 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque20.push(7);
        concurrentLinkedDeque20.push(8);
        concurrentLinkedDeque20.push(9);
        Integer removeFirstResult = concurrentLinkedDeque20.removeFirst();
        System.out.println("deque的第一个元素: " + removeFirstResult);

        /**
         * 23、removeLast():检索并删除此deque的最后一个元素。
         */
        ConcurrentLinkedDeque<Integer> concurrentLinkedDeque21 = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque21.push(10);
        concurrentLinkedDeque21.push(11);
        concurrentLinkedDeque21.push(12);
        Integer removeLastResult = concurrentLinkedDeque21.removeLast();
        System.out.println("deque的最后一个元素: " + removeLastResult);

        /**
         * 24、size():返回此deque中的元素数。
         */
        Integer size = concurrentLinkedDeque21.size();
        System.out.println("concurrentLinkedDeque21的元素个数为:" + size);



    }
}

四、总结
①、基于链接节点的无界并发 deque 。 并发插入,删除和访问操作可以跨多个线程安全执行。 一个 ConcurrentLinkedDeque 是许多线程将共享对公共集合的访问的适当选择。 像大多数其他并发集合实现一样,此类不允许使用 null 元素, ConcurrentLinkedDeque 是一个双向链表 。

②、ConcurrentLinkedDeque 使用了自旋 + CAS 的非阻塞算法来保证线程并发访问时的数据一致性。由于队列本身是一种双链表结构,所以虽然算法看起来很简单,但其实需要考虑各种并发的情况,实现复杂度较高,并且 ConcurrentLinkedDeque 不具备实时的数据一致性,实际运用中,如果需要一种线程安全的栈结构,可以使用 ConcurrentLinkedDeque。

③、关于 ConcurrentLinkedDeque 还有以下需要注意的几点:

1、ConcurrentLinkedDeque 的迭代器是弱一致性的,这在并发容器中是比较普遍的现象,主要是指在一个线程在遍历队列结点而另一个线程尝试对某个队列结点进行修改的话不会抛出 ConcurrentModificationException,这也就造成在遍历某个尚未被修改的结点时,在 next 方法返回时可以看到该结点的修改,但在遍历后再对该结点修改时就看不到这种变化。
2、size 方法需要遍历链表,所以在并发情况下,其结果不一定是准确的,只能供参考。

并发_住手丶让我来的博客 - CSDN 博客

 

 
posted @ 2024-06-27 16:06  CharyGao  阅读(31)  评论(0编辑  收藏  举报