正确实施生产者 - 消费者场景和“优雅”终止线程池

时间:2011-03-16 13:29:57

标签: java multithreading producer-consumer

我正在开发我的第一个多线程项目,因此有一些我不确定的事情。有关我的设置的详细信息位于previous question,简而言之:我有一个由Executors.newFixedThreadPool(N)实现的线程池。给一个线程一个操作,该操作对本地和远程资源执行一系列查询,并迭代填充ArrayBlockingQueue,而其余线程在队列上调用take()方法并处理队列中的对象。

即使小型和监督测试似乎运行正常,我也不确定我如何处理特殊情况,例如开头(队列还没有项目),结束(队列已清空),以及任何最终{{ 1}}。我在SO上做了一些阅读,然后由GoetzKabutz引导我阅读了两篇非常好的文章。共识似乎是不应忽视这些例外。但是我不确定所提供的示例是如何与我的情况相关的,我没有在我的代码中的任何地方调用InterruptedExceptions ......说到这一点,我不确定我是否应该这样做......

总结一下,鉴于下面的代码,我如何最好地处理特殊情况,例如终止条件和InterrruptedExceptions?希望问题有意义,否则我会尽力进一步描述。

提前致谢,


编辑:我一直在努力实施一段时间,我遇到了一个新的打嗝,所以我想我会更新情况。我遇到了thread.interrupt()的不幸,这很可能是由于线程池的不完全关闭/终止造成的。一旦我发现我可以使用ConcurrentModificationException我尝试了,然后由于未同步的isTerminated()我得到IllegalMonitorStateException。代码的当前状态如下:

我已经听过@ Jonathan的回答中的一些建议,但是我不认为他的建议与我需要/想要的一样。背景故事与我上面提到的相同,相关的代码如下:

持有/管理池的类,以及提交runnables:

wait()

元素通过位于单独类中的以下代码添加到队列中:

public void serve() {
    try {
        this.started = true;
        pool.execute(new QueryingAction(pcqs));
        for(;;){
            PathwayImpl p = bq.take();

            if (p.getId().equals("0")){
                System.out.println("--DEBUG: Termination criteria found, shutdown initiated..");
                pool.shutdown();
                            // give 3 minutes per item in queue to finish up
                pool.awaitTermination(3 * bq.size(), TimeUnit.MINUTES);
                break;
            }
            int sortMethod = AnalysisParameters.getInstance().getSort_method();
            pool.submit(new AnalysisAction(p)); 
        }
      } catch (Exception ex) {
          ex.printStackTrace();
          System.err.println("Unexpected error in core analysis, terminating execution!");
          System.exit(0);
      }finally{   pool.shutdown();     }
}

public boolean isDone(){
    if(this.started)
        return pool.isTerminated();
    else
        return false;
    }

...... this.queue.offer(path, offer_wait, TimeUnit.MINUTES); 而不是offer()背后的动机正如乔纳森所提到的那样。不可预见的块很烦人,很难弄清楚,因为我的分析花了很长时间。因此,如果由于坏块而失败,或者它只是处理数字,我需要知道相对较快...


最后;这是我的测试类中的代码,我在其中检查“并发服务”(此处命名为cs)与要分析的其余对象之间的交互:

take()

我意识到这是一个非常长的问题,但我试图详细而具体。希望它不会太拖累,我道歉,以防它... ...

1 个答案:

答案 0 :(得分:1)

不使用take哪个块,而是使用更像这样的东西:

PathwayImpl p = null;
synchronized (bq) {
    try {
        while (bq.isEmpty() && !stopSignal) {
            bq.wait(3000); // Wait up to 3 seconds and check again
        }

        if (!stopSignal) {
            p = bq.poll();
        }
    }
    catch (InterruptedException ie) {
        // Broke us out of waiting, loop around to test the stopSignal again
    }
}

这假设该块包含在某种while (!stopSignal) {...}

然后,在添加到队列的代码中,执行以下操作:

synchronized (bq) {
    bq.add(item);
    bq.notify();
}

至于InterruptedException,它们很适合用信号通知线程立即测试停止信号,而不是等到下一次超时测试。我建议再次测试你的停止信号,并可能记录异常。

我在发出恐慌信号时使用它们,而不是正常关机,但很少需要这种情况。