首页 > 代码库 > 关于java同步包中ConcurrentLinkedQueue类的深入分析与理解
关于java同步包中ConcurrentLinkedQueue类的深入分析与理解
一,官方描述
一个基于连接节点的无界线程安全队列。这个队列的顺序是先进先出。队列头部的元素是留在队列中时间最长的,队列尾部的元素是留在队列中时间最短的。新元素被插入到元素的尾部,队列从队列的头部检索元素。当许多线程共享访问同一个集合时,这个类是不二选择。这个队列不允许有null元素。
这个实现基于一种被描述为简单,快速,实用的非阻塞和阻塞公布队列算法而提供的一种有效的空闲等待算法。
注意,不像大多数集合,size方法的操作不是常量时间的,由于是异步队列,决定了元素的数量需要遍历真个元素集。
这个类和它的迭代器实现了Collection和Iterator接口的所有可选方法。
二,源码分析
如下代码所示,这个类继承了AbstractQueue抽象类,实现了Queue和Serializable接口。
public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, java.io.Serializable
分析这个类的源码,必须先从它的静态内部类Node开始。在Node类中,Node的插入和比较操作都是使用底层的Unsafe类来完成的,也就是说,这个Node类自身已经是线程安全的。
在这个类的变量中,head和tail对象是使用volatile来修饰的,我前面的一片文章中说过,volatile是线程安全的,但不是原子操作。在这个类中,由于每个Node变量都是volatile修饰,因此使用指针获取next或者previous节点时,也是线程安全的。
在这个类中需要注意size方法,源代码如下:
public int size() { int count = 0; for (Node<E> p = first(); p != null; p = succ(p)) if (p.item != null) // Collection.size() spec says to max out if (++count == Integer.MAX_VALUE) break; return count; }
从以上源代码可以看出,获取size的时间并不是常量时间,而是O(n)时间。这也是一种以时间换取安全性的折中策略。
在分析源码时你会发现,像这个类中得remove,peek,pool等操作中都没有锁或者其它持有线程安全的条件,其实它这里的线程安全,全部都在Node静态类中完成了,因为在这个源码中不管你用哪一个方法,其实都是会调用Node中的next,而Node中得方法都是线程安全的,因此这些操作也都是线程安全的。
三,总结
1,这个类是基于队列的链表,即先进先出原则
2.这个类的size方法花费O(n)时间
3.这个类是线程安全的,它的Iterator也是线程安全的