使用ConcurrentLinkedQueue惨痛的教训

Posted .x->y=z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用ConcurrentLinkedQueue惨痛的教训相关的知识,希望对你有一定的参考价值。

转自:http://blog.csdn.net/jackpk/article/details/49634577

服务端原本有个定时任务对一个集合ArrayList 中的消息做处理。 因为考虑到处理消息是先进先出原则,所以优化的时候考虑改用ConcurrentLinkedQueue 当时没仔细深入研究过这个集合就匆匆上线了。结果刚上线第二天就出问题了。服务端一次优化演变成了一个缺陷,还好及时回退了版本,后果才不是很严重。回退后对ConcurrentLinkedQueue 做了一个简单的测试代码,如下:

 1 import java.util.concurrent.ConcurrentLinkedQueue;
 2 import java.util.concurrent.CountDownLatch;
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 public class ConcurrentLinkedQueueTest {
 7     
 8     private static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
 9     
10     private static int count = 100000;
11     
12     private static int count2 = 2; // 线程个数
13     
14     private static CountDownLatch cd = new CountDownLatch(count2);
15     
16     public static void dothis() {
17         for (int i = 0; i < count; i++) {
18             queue.offer(i);
19         }
20     }
21     
22     public static void main(String[] args) throws InterruptedException {
23         long timeStart = System.currentTimeMillis();
24         ExecutorService es = Executors.newFixedThreadPool(4);
25         ConcurrentLinkedQueueTest.dothis();
26         for (int i = 0; i < count2; i++) {
27             es.submit(new Poll());
28         }
29         cd.await();
30         System.out.println("cost time " + (System.currentTimeMillis() - timeStart) + "ms");
31         es.shutdown();
32     }
33     
34     static class Poll implements Runnable {
35         @Override
36         public void run() {
37             //while (queue.size() > 0) {    // 效率低,每次都需要计算整个队列的个数
38             while (!queue.isEmpty()) {
39                 System.out.println(queue.poll());
40             }
41             cd.countDown();
42         }
43     }
44 }

运行结果:

  costtime 2360ms

改用while (queue.size() > 0)后运行结果:

  cost time 46422ms

结果居然相差那么大,看了下ConcurrentLinkedQueue的API 原来.size() 是要遍历一遍集合的,难怪那么慢,所以尽量要避免用size而改用isEmpty().

总结了下, 在缺乏性能测试的情况下,对自己的编程要求更加要严格,特别是在生产环境下更是要小心谨慎。

以上是关于使用ConcurrentLinkedQueue惨痛的教训的主要内容,如果未能解决你的问题,请参考以下文章

ConcurrentLinkedQueue

ConcurrentLinkedQueue 1.8 源码浅析

java-ConcurrentLinkedQueue 简单使用

Java同步数据结构之ConcurrentLinkedQueue

ConcurrentLinkedQueue

JUC源码分析-集合篇ConcurrentLinkedQueue