`
wwty
  • 浏览: 537223 次
  • 性别: Icon_minigender_1
  • 来自: 北京-郑州
社区版块
存档分类
最新评论

使用ConcurrentLinkedQueue惨痛的教训

阅读更多

文章来源:

http://blog.csdn.net/Kanepan/archive/2010/07/01/5706488.aspx

 

前两天写了个生产消费的程序,根据需求用了ConcurrentLinkedQueue,然后又用到了其size方法,所以转载此篇文章。

 

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

回退后对ConcurrentLinkedQueue 做了一个简单的测试代码如下:

view plaincopy to clipboardprint?
import java.util.concurrent.ConcurrentLinkedQueue;  
import java.util.concurrent.CountDownLatch;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
public class ConcurrentLinkedQueueTest {  
    private static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();  
    private static int count = 100000;  
    private static int count2 = 2; // 线程个数  
    private static CountDownLatch cd = new CountDownLatch(count2);  
    public static void dothis() {  
        for (int i = 0; i < count; i++) {  
            queue.offer(i);  
        }  
    }  
    public static void main(String[] args) throws InterruptedException {  
        long timeStart = System.currentTimeMillis();  
        ExecutorService es = Executors.newFixedThreadPool(4);  
        ConcurrentLinkedQueueTest.dothis();  
        for (int i = 0; i < count2; i++) {  
            es.submit(new Poll());  
        }  
        cd.await();  
        System.out.println("cost time "  
                + (System.currentTimeMillis() - timeStart) + "ms");  
        es.shutdown();  
    }  
    static class Poll implements Runnable {  
        @Override  
        public void run() {  
//          while (queue.size()>0) {  
            while (!queue.isEmpty()) {  
                System.out.println(queue.poll());  
            }  
            cd.countDown();  
        }  
    }  
}  

 

运行结果:

costtime 2360ms

改用while (queue.size()>0)后

运行结果:

cost time 46422ms

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

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

分享到:
评论
3 楼 287854442 2011-08-26  
有必要这样实现吗?
queue.poll()方法如果队列为空,返回null
可以这样实现:
while(true){
     Integer i = queue.poll();
     if (i==null){
          break;
     }else{
           syso(i);
     }
}

2 楼 wwty 2011-06-22  
xnxqs 写道
你这个程序还是有隐患的。。。
while (!queue.isEmpty()) {   
                System.out.println(queue.poll());   
            } 

poll涉及到删除元素的动作,而这一部分的操作已经是原子性的了,所以你必须加锁,可以参考这个。http://stackoverflow.com/questions/435069/java-util-concurrentlinkedqueue/435941


呵呵,谢谢了,确实是这样:
That last one is not threadsafe, as it is very possible that between the time isEmpty is called and the time poll is called, other threads will have added or removed items from the queue. The threadsafe way to perform this is like this:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}
1 楼 xnxqs 2011-06-20  
你这个程序还是有隐患的。。。
while (!queue.isEmpty()) {   
                System.out.println(queue.poll());   
            } 

poll涉及到删除元素的动作,而这一部分的操作已经是原子性的了,所以你必须加锁,可以参考这个。http://stackoverflow.com/questions/435069/java-util-concurrentlinkedqueue/435941

相关推荐

Global site tag (gtag.js) - Google Analytics