ExecutorService的多个newSingleThreadExecutor和newFixedThreadPool之间有什么区别?

6

在我的应用程序中,我有4个不同的进程,它们会一直运行,但会有一些小的暂停。

当前版本的代码使用单独的传统线程来执行每个进程:

Thread nlpAnalyzer = new Thread(() -> {

    // infine lop for auto restore in case of crash
    //noinspection InfiniteLoopStatement
    while (true) {
        try {
            // this method should run permanently, pauses implemented internally
            NLPAnalyzer.analyzeNLP(dbCollection);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

nlpAnalyzer.setName("im_nlpAnalyzer");
nlpAnalyzer.start();

现在我想使用ExecutorService重构这段代码。为了做到这一点,我可以采用至少两种方法:
  • newFixedThreadPool(numOfProc)
  • numOfProc * newSingleThreadExecutor()
我的问题是:
  1. 有没有理由我应该更喜欢其中一种选择?
  2. 生成一个包含X个线程的线程池或者生成X个newSingleThreadExecutor哪个更被接受?
  3. 每种方法的优缺点是什么?

选项1更常见,开销最小。 - Spotted
另外,你可以将无限循环内的代码重写为一个“Runnable”,在运行时以执行器服务的形式再次发布自己。这样,即使在单个线程上,也可以运行多个任务。 - S.D.
2个回答

4

假设每个任务都是一个无限循环,我会使用

newCachedThreadPool();

这将为每个需要它的任务创建一个线程(而不是更多)。
使用单个线程池的好处是,您可以单独关闭线程池,或给每个线程命名,但如果您不需要这些功能,则只是额外的开销。
注意:您可以使用setName("My task")更改线程的名称,这对于调试/分析目的可能很有用。
使用ExecutorService的技巧之一是它捕获任何未捕获的异常/错误,并将其放置在返回的Future对象中。通常,这个Future被丢弃,这意味着如果您的任务意外终止,它可能会悄悄地失败。
我建议您在循环的外部使用try/catch(Throwable)并记录它,以便您可以查看线程是否意外终止。例如OutOfMemoryError。

据我所知,即使在newFixedThreadPool中,我也可以为单独的线程分配一个名称,而不仅仅是在newSingleThreadExecutor中。定义1个包含X个线程的newFixedThreadPool和X个newSingleThreadExecutor之间是否存在性能差异? - Mike
1
@MikeB。你可以分配一个单独的线程名称,但不是基于任务目的的名称,这可能更有用。我会做任何你觉得更清晰的事情,无论你选择哪种解决方案,Thread仍然会完成工作。 - Peter Lawrey

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接