多个消费者从ConcurrentLinkedQueue两次轮询相同的值

时间:2013-10-11 06:22:03

标签: java multithreading

我广泛使用ConcurrentLinkedQueue进行多任务排队任务排队,之前从未遇到过这个问题。场景如下:

  1. 在我的队列中填写一些任务
  2. 运行将从队列
  3. 汇集任务的多个线程(在此特定情况下为2)
  4. 当队列不为空时,从队列中汇集并完成工作。
  5. 问题是,我的消费者正在汇集第一个元素TWICE 。为了避免混淆,我已经检查了队列中的重复元素元素,但没有。到底是怎么回事?我不知道为什么,但同步queue.poll()没有解决这个问题。如何解决这个问题?

    我的队列轮询同步包装器(我以前不需要它,这仍然没有帮助) 编辑:正如我所指出的,它没有帮助,但我不得不尝试。提出正确的方法。

    public class MultipleConsumerBlockingQueue<T> extends ConcurrentLinkedQueue<T> {
        private static final long serialVersionUID = 7994932568441881715L;
        private Logger log = LoggerFactory.getLogger(MultipleConsumerBlockingQueue.class);
    
        @Override
        public synchronized T poll() {
            T item = super.poll();
            return item;
        }
    
    }
    

    消费线程的一部分

            @Override
            public void run() {
                try {
                    AdvancedSearchAgent agent = new AdvancedSearchAgent();
                    while ((dp = queue.poll()) != null) {
                        log.info("**** for publication dates: {} - {}", sdf.format(dp.getFromDate()), sdf.format(dp.getToDate()));
                        agent.searchByPublicationDate(dp.getFromDate(), dp.getToDate());
                        log.info("Expected results count {} on {} pages", agent.getResultsCount(), agent.getPagesCount());
                        iterateOverResult(agent, handler);
                    }
                } catch (Exception ex) {
                    log.error("Unhanded error occured ****. Exiting method *****", ex);
                }
    
            }
    

    生成输出:

    08:05:15.171 [main] INFO  ****  - Generated 10 date intervals for querying
    08:05:15.174 [main] INFO  ****  - Created inner task 1
    08:05:15.174 [main] INFO  ****  - Created inner task 2
    Czas wykonania= 0 sekund  0 godzin 0 minut 0 sekund
    08:05:15.178 [pool-2-thread-1] INFO  **** - **** for publication dates: 01-02-2013 - 03-03-2013
    08:05:15.178 [pool-2-thread-2] INFO  **** - ****  for publication dates: 01-02-2013 - 03-03-2013
    

    编辑:

    这是队列中的项目转储。没有重复。

       1# -> Wt 2013-01-01 : Cz 2013-01-31
       2# -> Pt 2013-02-01 : N 2013-03-03
       3# -> Pn 2013-03-04 : Śr 2013-04-03
       4# -> Cz 2013-04-04 : So 2013-05-04
       5# -> N 2013-05-05 : Wt 2013-06-04
       6# -> Śr 2013-06-05 : Pt 2013-07-05
       7# -> So 2013-07-06 : Pn 2013-08-05
       8# -> Wt 2013-08-06 : Cz 2013-09-05
       9# -> Pt 2013-09-06 : N 2013-10-06
      10# -> Pn 2013-10-07 : Pt 2013-10-11
    

3 个答案:

答案 0 :(得分:2)

ConcurrentLinkedQueue几乎不可能被打破。多年来,它已经在文学上的数百万个应用程序中进行了测试,并保证您不会两次轮询相同的元素。

我看不出你在哪里定义dp。如果这不是局部变量,我会感觉到一个潜在的候选者......尝试将其变成局部变量并查看它是否仍然存在。

这听起来可能很愚蠢,但要确保你从一个相同的ConcurrentLinkedQueue对象进行轮询(这通常是愚蠢的事情)。

答案 1 :(得分:2)

我有常见的错误 - 它涉及Dateformat的NonThreadSafety。从队列轮询就好了,只生成了有错误的日志。 sdf是由worker共享的SimpleDateFormat对象(起初它应该只是单线程,所以没有人关心)。由于它不是线程安全的,因此形成了错误的日期。很伤心,我以前没有抓住它。 感谢所有的评论和指出。

答案 2 :(得分:0)

您的synchronized方法永远不会按预期工作,因为ConcurrentLinkedQueue不使用Java Monitor Pattern进行线程安全。它使用了here解释的不同方法。