`

集合框架 Queue篇(3)---ConcurrentLinkedQueue

 
阅读更多
Queue

------------
1.ArrayDeque,
2.PriorityQueue,
3.ConcurrentLinkedQueue,

4.DelayQueue,
5.ArrayBlockingQueue,
6.LinkedBlockingQueue,
7.LinkedBlockingDeque
8.PriorityBlockingQueue,
9.SynchronousQueue
------------

---------------------------------------

ConcurrentLinkedQueue(基于链表的无界线程安全队列)

提供了高效的、可伸缩的、线程安全的非阻塞FIFO队列。


先来了解一下AtomicReferenceFieldUpdater的API:

public abstract class AtomicReferenceFieldUpdater<T,V> extends Object
基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。该类用于原子数据结构,该结构中同一节点的几个引用字段都独立受原子更新控制。例如,树节点可能声明为

class Node {
   private volatile Node left, right;

   private static final AtomicReferenceFieldUpdater leftUpdater =
     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
   private static AtomicReferenceFieldUpdater rightUpdater =
     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");

   Node getLeft() { return left;  }
   boolean compareAndSetLeft(Node expect, Node update) {
     return leftUpdater.compareAndSet(this, expect, update);
   }
   // ... and so on
 }

其中的compareAndSet调用Sun的UnSafe的compareAndSwapInt方法,此方法是native方法,compareAndSwapInt是基于CPU的CAS原语来实现的。

CAS(Compare -And -Swap)简单来说就是由CPU比较内存位置上的值是否与当前值expect相同,如果是则将其设置为update,如果不是则返回false。
基于CAS的操作可认为是无阻塞的,并且由于CAS操作时CPU原语,因此其性能会好于之前同步锁的方式。

ConcurrentLinkedQueue并未使用原子化的引用,而是使用普通的volatile引用来代表每一个节点,并通过基于反射的AtomicReferenceFieldUpdater来进行更新。原子化的域更新器类,代表着已存在的volatile域基于反射的“视图”,使得CAS能够用于已有的volatile域。更新器类没有构造函数,为了创建,需要调用newUpdater的工厂方法,声明类和域的名称。域更新器并不依赖特定的实例;它可以用于更新目标类任何实例的目标域。更新器类提供的原子保护比普通的原子类差一些,因为不能保证底层的域不被直接修改----compareAndSet和算术方法只在其他线程使用原子化的域更新器方法时保证其原子性。
在ConcurrentLinkedQueue中,更新Node的next域是通过使用nextUpdater的compareAndSet方法实现的。这个有点迂回的方案是因性能原因使用的。对于频繁分配的、生命周期短暂的对象,比如队列的链接节点,减少每个Node的AtomicReference创建,对于减小插入操作的开销是非常有效的。

----
ABA问题是因为算法中误用比较交换引起的反常现象,节点被循环使用(主要存在于不能被GC的环境中)。在某些算法中把V的值由A转换为B,再转换为A任然记为一次改变,这时需要重新进行算法中的某些步骤。
简单的解决方案:更新一对值,包括引用和版本号,而不是仅更新该值的引用。即使值由A改为B,又改回A,版本号也是不同的。

------------------------------

/**
*ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。
*队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。
*当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。 
*
*此实现采用了基于CAS的原子操作,性能高于synchronized方法。
*/
public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, java.io.Serializable {
  
    /*
    *采用基于AtomicReferenceFieldUpdater的Node结构,内部实现采用了基于CAS的原子操作
    */
    private static class Node<E> {
        private volatile E item;
        private volatile Node<E> next;

        private static final AtomicReferenceFieldUpdater<Node, Node>  nextUpdater =
               AtomicReferenceFieldUpdater.newUpdater (Node.class, Node.class, "next");
        private static final AtomicReferenceFieldUpdater<Node, Object> itemUpdater =
               AtomicReferenceFieldUpdater.newUpdater (Node.class, Object.class, "item");

        Node(E x) { item = x; }

        Node(E x, Node<E> n) { item = x; next = n; }

        E getItem() {
            return item;
        }

        boolean casItem(E cmp, E val) {
            return itemUpdater.compareAndSet(this, cmp, val);
        }

        void setItem(E val) {
            itemUpdater.set(this, val);
        }

        Node<E> getNext() {
            return next;
        }

        boolean casNext(Node<E> cmp, Node<E> val) {
            return nextUpdater.compareAndSet(this, cmp, val);
        }

        void setNext(Node<E> val) {
            nextUpdater.set(this, val);
        }

    }

    //定义tailUpdater、headUpdater 分别实现对头尾的cas操作
    private static final AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> tailUpdater =
            AtomicReferenceFieldUpdater.newUpdater(ConcurrentLinkedQueue.class, Node.class, "tail");
    private static final AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> headUpdater =
            AtomicReferenceFieldUpdater.newUpdater(ConcurrentLinkedQueue.class,  Node.class, "head");

    private boolean casTail(Node<E> cmp, Node<E> val) {//对尾部cas操作
        return tailUpdater.compareAndSet(this, cmp, val);
    }

    private boolean casHead(Node<E> cmp, Node<E> val) {//对头部cas操作
        return headUpdater.compareAndSet(this, cmp, val);
    }

    /**
     * 头结点(虚节点,第一个节点其实是head.next())
     */
    private transient volatile Node<E> head = new Node<E>(null, null);

    /** 尾节点,队列的最后一个元素 **/
    private transient volatile Node<E> tail = head;

    /**
     * 空构造
     */
    public ConcurrentLinkedQueue() {}

    /**
     * 通过集合构建队列
     */
    public ConcurrentLinkedQueue(Collection<? extends E> c) {
        for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
            add(it.next());
    }

    // Have to override just to update the javadoc
    /**
     * 插入元素(在队尾)
     */
    public boolean add(E e) {
        return offer(e);
    }

    /**
     * 插入元素(在队尾)
     */
    public boolean offer(E e) {
        if (e == null) throw new NullPointerException();
        Node<E> n = new Node<E>(e, null);//新节点n
        for (;;) {//放到无限循环中,直到找到正确的位置并插入
            Node<E> t = tail;
            Node<E> s = t.getNext();
            if (t == tail) {//再次验证
                if (s == null) {
                    if (t.casNext(s, n)) {//如果t的next为s,则把n设为t的next
                        casTail(t, n);//t为尾的情况下,把n设为尾节点
                        return true;
                    }
                } else {//如果s不为空,判断t是否为尾,是的情况下把s设为尾节点
                    casTail(t, s);
                }
            }
        }
    }

    public E poll() {
        for (;;) {
            Node<E> h = head;
            Node<E> t = tail;
            Node<E> first = h.getNext();
            if (h == head) {
                if (h == t) {//如果头尾是同一节点
                    if (first == null)//空队的情况
                        return null;
                    else
                        casTail(t, first);//用cas把h的next节点设置为尾节点
                } else if (casHead(h, first)) {//用cas把h的next节点first设置为新的头节点
                    E item = first.getItem();
                    if (item != null) {
                        first.setItem(null);//头结点是一个虚节点
                        return item;
                    }
                    // else skip over deleted item, continue loop,
                }
            }
        }
    }

    public E peek() { // 和poll操作类似,只是不删除元素,只是返回头节点的next的item
        for (;;) {
            Node<E> h = head;
            Node<E> t = tail;
            Node<E> first = h.getNext();
            if (h == head) {
                if (h == t) {
                    if (first == null)
                        return null;
                    else
                        casTail(t, first);
                } else {
                    E item = first.getItem();
                    if (item != null)
                        return item;
                    else // remove deleted node and continue
                        casHead(h, first);
                }
            }
        }
    }

    /**
     * 和poll/peek类似,不过返回的是头节点的next节点Node。(在下面的方法中有调用,如size()等)
     */
    Node<E> first() {
        for (;;) {
            Node<E> h = head;
            Node<E> t = tail;
            Node<E> first = h.getNext();
            if (h == head) {
                if (h == t) {
                    if (first == null)
                        return null;
                    else
                        casTail(t, first);
                } else {
                    if (first.getItem() != null)
                        return first;
                    else // remove deleted node and continue
                        casHead(h, first);
                }
            }
        }
    }


    public boolean isEmpty() {
        return first() == null;
    }

    public int size() {
        int count = 0;
        for (Node<E> p = first(); p != null; p = p.getNext()) {
            if (p.getItem() != null) {
                // Collections.size() spec says to max out
                if (++count == Integer.MAX_VALUE)
                    break;
            }
        }
        return count;
    }

    public boolean contains(Object o) {
        if (o == null) return false;
        for (Node<E> p = first(); p != null; p = p.getNext()) {
            E item = p.getItem();
            if (item != null &&
                o.equals(item))
                return true;
        }
        return false;
    }

    public boolean remove(Object o) {
        if (o == null) return false;
        for (Node<E> p = first(); p != null; p = p.getNext()) {
            E item = p.getItem();
            if (item != null &&
                o.equals(item) &&
                p.casItem(item, null))
                return true;
        }
        return false;
    }

    public Object[] toArray() {
        // Use ArrayList to deal with resizing.
        ArrayList<E> al = new ArrayList<E>();
        for (Node<E> p = first(); p != null; p = p.getNext()) {
            E item = p.getItem();
            if (item != null)
                al.add(item);
        }
        return al.toArray();
    }

    public <T> T[] toArray(T[] a) {
        // try to use sent-in array
        int k = 0;
        Node<E> p;
        for (p = first(); p != null && k < a.length; p = p.getNext()) {
            E item = p.getItem();
            if (item != null)
                a[k++] = (T)item;
        }
        if (p == null) {
            if (k < a.length)
                a[k] = null;
            return a;
        }

        // If won't fit, use ArrayList version
        ArrayList<E> al = new ArrayList<E>();
        for (Node<E> q = first(); q != null; q = q.getNext()) {
            E item = q.getItem();
            if (item != null)
                al.add(item);
        }
        return (T[])al.toArray(a);
    }

  ……

}
分享到:
评论

相关推荐

    Queue-Server-SO

    2. **并发容器**:Java集合框架提供了多种适用于并发环境的容器,如ConcurrentLinkedQueue、BlockingQueue等,它们能有效支持线程安全的队列操作,确保数据的一致性和完整性。 3. **网络编程**:队列服务器需要接收...

    全面接触java集合框架(word版)

    Java集合框架是Java编程语言中的一个核心特性,它为存储、管理和操作对象提供了一套统一的接口和实现。这个框架包括各种接口、类和算法,使得开发者能够更加高效地处理对象集合,而无需关注底层数据结构的实现细节。...

    JAVA集合框架

    Java集合框架是Java编程语言中一个非常核心的部分,它为数据存储和操作提供了丰富的类库。这个框架使得开发者能够高效地处理各种数据结构,如列表、队列、映射等,而无需关注底层实现的复杂性。在Java集合框架中,...

    20个最佳的Java集合框架面试题目.zip

    1. **集合与接口**:Java集合框架包括List、Set和Queue等接口,它们都是继承自Collection接口。ArrayList、LinkedList、HashSet、TreeSet、LinkedList和PriorityQueue是常见的实现类。 2. **ArrayList与LinkedList*...

    Java--collection.rar_SEP_java 集合

    首先,集合框架的基础是`Collection`接口,它是所有单值容器的父接口,包括`List`, `Set`和`Queue`等子接口。`List`接口用于存储有序的元素,允许重复;`Set`接口则存储不重复的元素,无序;而`Queue`接口则定义了...

    implement-queue-module2

    1. **Queue接口**:Java.util.Queue是Java集合框架的一部分,提供了各种队列操作的方法,如add()、remove()、peek()等。实现这个接口意味着我们的队列模块将具备标准的队列行为。 2. **接口实现**:由于Queue是一个...

    java 面试题 集合

    Java集合框架是Java编程语言中的核心部分,它提供了一种高效、灵活的数据组织方式,使得开发者可以方便地存储和操作对象。在Java面试中,集合相关的知识点常常是考察的重点,因为它们涉及到数据结构、内存管理和多...

    Java程序设计教材 第十一章框架

    首先,集合框架的核心接口有List、Set、Queue和Map。List接口允许元素保持特定的顺序,比如ArrayList和LinkedList。Set接口不保证元素的顺序,但不允许重复元素,例如HashSet和TreeSet。Queue接口则用于实现队列操作...

    java集合类的代码

    Java集合框架包括接口(如List、Set、Queue等)和实现这些接口的类(如ArrayList、HashSet、LinkedList等)。这个压缩包文件“Collection”很可能包含了关于Java集合类的一些示例代码,这些代码可以用于理解和学习...

    30个Java经典的集合面试题!.zip

    在Java编程语言中,集合框架是面试中经常讨论的话题,因为它构成了处理对象数组的基础。面试官经常通过提问关于集合的问题来评估候选人的基础知识、问题解决能力和实践经验。以下是一些Java集合框架中的关键知识点,...

    Java学习超强笔记

    4. **数组与集合框架** - 数组:一维、二维数组的声明、初始化和操作。 - 集合接口:List、Set和Queue等,以及ArrayList、LinkedList、HashSet、LinkedHashSet、Stack和Queue的具体实现。 - Map接口:HashMap、...

    JavaExamples2快速点击·所有集合源代码

    在Java编程语言中,集合框架是核心库的重要组成部分,它为数据存储提供了丰富的类和接口。"JavaExamples2快速点击·所有集合源代码"显然是一份包含与Java集合相关的示例代码的压缩包,旨在帮助开发者更好地理解和...

    JAVA核心知识点整理.zip

    3. **集合框架**: - **List、Set、Queue和Map接口**:各自的特点及常用实现类(ArrayList、LinkedList、HashSet、HashMap等)。 - **泛型**:引入泛型以增强类型安全性和代码重用性。 - **迭代器**:遍历集合...

    数据结构面试专题.docx

    3. **Java集合框架** - **Collection接口**:所有集合类的顶级接口,包含List、Set等子接口。 - **Map接口**:不继承Collection,提供键值对映射,如HashMap、TreeMap和LinkedHashMap。 - **Set接口**:不包含...

    Java经典面试题全集-绝对经典

    4. **集合框架**: - **List、Set、Queue**:ArrayList、LinkedList、HashSet、HashMap、TreeMap、PriorityQueue等的区别和使用。 - **泛型**:理解泛型的基本概念,类型擦除,通配符,Bounds限制等。 - **并发...

    【Java面试资料】-(机构内训资料)深圳-乐信-Java高级

    3. **集合框架** - **ArrayList与LinkedList**:它们的实现方式及应用场景,性能比较。 - **HashMap与HashTable**:线程安全、并发性,以及HashMap的扩容机制。 - **Set与Queue**:HashSet、TreeSet、LinkedList...

    数据结构面试题及正确答案

    4. **Java集合框架**: - **Collection**接口是所有单列集合的父接口,包括`List`、`Set`。 - **Map**接口则用于存储键值对,如`HashMap`、`TreeMap`等。 - **集合之间的继承关系**:`ArrayList`和`LinkedList`...

    java基础之集合

    Java集合框架是Java编程语言中的一个核心特性,它为存储、管理和操作对象提供了一组统一的接口和类。集合框架使得在处理数据时更加高效,同时也增强了代码的可读性和可维护性。对于初学者来说,理解并熟练掌握Java...

    util包

    在Java编程语言中,`util`包(全称为`java.util`)是一个极其重要的核心包,它包含了大量用于实现常用数据结构、集合框架、日期时间处理、随机数生成、I/O流操作、国际化以及各种实用工具类的接口和类。这个包是Java...

    java面试100题目

    这份“java面试100题目”的资料涵盖了Java编程、并发编程、JVM、集合框架、Spring框架、数据库以及设计模式等多个核心领域。下面,我们将深入探讨这些关键知识点。 1. **Java基础** - **变量与数据类型**:包括...

Global site tag (gtag.js) - Google Analytics