ConcurrentLinkedQueue API 说明

public class
ConcurrentLinkedQueue
extends AbstractQueue<E>
implements Serializable Queue<E>
java.lang.Object
     java.util.AbstractCollection<E>
        java.util.AbstractQueue<E>
            java.util.concurrent.ConcurrentLinkedQueue<E>
Class Overview
An unbounded thread-safe queue based on linked nodes. This queue orders elements FIFO (first-in-first-out). 
The head of the queue is that element that has been on the queue the longest time. 
The tail of the queue is that element that has been on the queue the shortest time. 
New elements are inserted at the tail of the queue, and the queue retrieval operations obtain elements at the head of the queue. 
A ConcurrentLinkedQueue is an appropriate choice when many threads will share access to a common collection. 
This queue does not permit null elements.

它是一个基于链接节点的无界线程安全队列。该队列的元素遵循先进先出的原则。头是最先加入的,尾是最近加入的。
插入元素是追加到尾上。提取一个元素是从头提取。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。
该队列不允许null元素
This implementation employs an efficient "wait-free" algorithm based on one described in Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by .
此实现采用了有效的“无等待 (wait-free)”算法,该算法基于 Maged M. Michael 和 Michael L. Scott 合著的  Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms 中描述的算法。 
Beware that, unlike in most collections, the size method is NOT a constant-time operation. Because of the asynchronous nature of these queues, 
determining the current number of elements requires a traversal of the elements.
注意和大多数集合不一样。得到元素个数所花的时间是不确定。由于该队列的异步特性,确定当前的元素数量需要遍历的元素
This class and its iterator implement all of the optional methods of the Collection and Iterator interfaces.
这个类和它的迭代器实现了Collection和Iterator接口的所有可选方法。
Memory consistency effects: As with other concurrent collections,
actions in a thread prior to placing an object into a ConcurrentLinkedQueue happen-before actions subsequent to the access or removal of that element from the ConcurrentLinkedQueue in another thread.
内存一致性效果:和其他并发集合一样。把一个元素放入到队列的线程的优先级高与对元素的访问和移除的线程。
有三个函数需要注意的:

E      peek()
Gets but does not remove the element at the head of the queue.
  poll()
Gets and removes the element at the head of the queue, or returns null if there is no element in the queue.
public <T> T[]  toArray(T[] a)
    返回以恰当顺序包含此队列所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。如果指定的数组能容纳队列,则将该队列返回此处。否则,将分配一个具有指定数组的运行时类型和此队列大小的新数组。
    如果指定的数组能容纳队列,并有剩余的空间(即数组的元素比队列多),那么会将紧接队列尾部的元素设置为 null。
    像 toArray() 方法一样,此方法充当基于数组的 API 与基于 collection 的 API 之间的桥梁。更进一步说,此方法允许对输出数组的运行时类型进行精确控制,在某些情况下,这可以用来节省分配开销。
    假定 x 是只包含字符串的一个已知队列。以下代码用来将该队列转储到一个新分配的 String 数组:
         String[] y = x.toArray(new String[0]);
    注意,toArray(new Object[0]) 和 toArray() 在功能上是相同的。
    指定者:
        接口 Collection<E> 中的 toArray
    覆盖:
        类 AbstractCollection<E> 中的 toArray
    参数:
        a - 将用来存储队列元素的数组(如果该数组足够大);否则,将为此分配一个具有相同运行时类型的新数组 
    返回:
        包含此队列所有元素的数组 
    抛出:
        ArrayStoreException - 如果指定数组的运行时类型不是此队列中每个元素的运行时类型的超类型 
        NullPointerException - 如果指定数组为 null
size
public int size()
    返回此队列中的元素数量。如果此队列包含的元素数大于 Integer.MAX_VALUE,则返回 Integer.MAX_VALUE。
    需要小心的是,与大多数 collection 不同,此方法不是 一个固定时间操作。由于这些队列的异步特性,确定当前的元素数需要进行一次花费 O(n) 时间的遍历。
    指定者:
         接口 Collection<E> 中的 size
    指定者:
         类 AbstractCollection<E> 中的 size
    返回:
        此队列中的元素数
注意1:
ConcurrentLinkedQueue的.size() 是要遍历一遍集合的,很慢的,所以尽量要避免用size,
如果判断队列是否为空最好用isEmpty()而不是用size来判断.

注意问题1:
使用了这个ConcurrentLinkedQueue 类之后是否意味着我们不需要自己进行任何同步或加锁操作了呢?
我在网上找到了这个: http://stackoverflow.com/questions/435069/java-util-concurrentlinkedqueue/435941  // StackOverflow果然是个好地方啊……
也就是说,如果直接使用它提供的函数,比如:queue.add(obj); 或者 queue.poll(obj);,这样我们自己不需要做任何同步。
但如果是非原子操作,比如:
   1. if(!queue.isEmpty()) {  
   2.    queue.poll(obj);  
   3. }  

我们很难保证,在调用了isEmpty()之后,poll()之前,这个queue没有被其他线程修改。
所以对于这种情况,我们还是需要自己同步:
   1. synchronized(queue) {  
   2.     if(!queue.isEmpty()) {  
   3.        queue.poll(obj);  
   4.     }  
   5. }  

注意问题2:
主类
Java代码
   1. public class conn{  
   2.     public static void main(String[] args) throws Exception{  
   3.         Queue<String> queue=new ConcurrentLinkedQueue<String>();  
   4.         for(int i=0;i<1000000;i++){  
   5.            queue.add(String.valueOf(i));  
   6.         }  
   7.         int num=10;//线程人个数  
   8.         for(int i=0;i<num;i++){  
   9.            new ThreadConn(queue);  
  10.         }  
  11.   
  12.     }  
  13. } 

 线程类
Java代码
   1. public class ThreadConn implements Runnable{  
   2.     Queue<String> queue;  
   3.     public ThreadConn(Queue<String> queue){  
   4.         this.queue=queue;  
   5.         Thread thread=new Thread(this);  
   6.         thread.start();  
   7.     }  
   8.     public void run(){  
   9.         try{  
  10.             long sd=new Date().getTime();  
  11.             while(queue.poll()!=null){  
  12.                           //这里是业务逻辑  
  13.             }  
  14.             System.out.println (sn-sd);  
  15.         }catch(Exception e){  
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19. }  

  测试结果如下:
启动10个线程
31
0
0
0
0
500
390
297
0
0

启动1个线程
360
10还没有1个快,如果 poll这后的业务逻辑运行时间小 的话,多线程序没有任何意义,
反之如果poll这后的业务逻辑运行时间相当于Thread.sleep(1);多线程确实起作用! 
为什么会产生该原因?请参照《 Java非阻塞算法简介 》中关于“性能考虑”的介绍
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java海洋

你的鼓励,是我写下去的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值