7

我开始学习 ExecutorService 类。文档(和在线教程)说总是调用 ExecutorService.shutDown() 来回收资源。但是,文档还说,在您调用 shutdown() 后,将不会接受任何新任务。所以,我的问题是,每当我需要并行化数据处理时,我是否总是必须实例化一个新的 ExecutorService ?

现在我有一个可调用对象列表,我执行以下操作。

public void someMethod() {
 List<OuterCallable> outerCallables = getOuterCallables();
 ExecutorService executor = Executor.newFixedThreadPool(NUM_CPUS);
 executor.invokeAll(tasks);
 executor.shutDown();
}

但是,我的 OuterCallable 也使用 InnerCallable 拆分数据或并行执行数据处理。

public class OuterCallable implements Callable<Long> {
 public Long call() throws Exception {
  long result = 0L;

  List<InnerCallable> innerCallables = getInnerCallables();
  ExecutorServices executor = Executor.newFixedThreadPool(NUM_CPUS);
  executor.invokeAll(tasks);
  executor.shutDown();

  return result;
 }
}    

我不记得它是用于 ExecutorService 还是 Fork/Join 方法,但我记得文档和教程说操作数据的实际并行过程不应该涉及 I/O 操作,并且一切都应该在内存中完成。但是,在我的 InnerCallable 中,我实际上是在进行 JDBC 调用(此处未显示)。

最终,我使用 ExecutorService 的方式有效,但我仍然有挥之不去的担忧。

  1. 我的方法是否高于使用 ExecutorService 的良好编程实践?
  2. 我应该使用 ExecutorService 的单例实例吗?
  3. 我不仅应该避免在我的并行方法中进行 I/O 操作,而且还应该避免 JDBC 调用吗?

作为最后一个问题,我试图对 Fork/Join 与 ExecutorService 进行一些研究。我遇到了一篇彻底抨击 Fork/Join API/类的文章。学习 Fork/Join 是否值得?我看到了一些关于 stackoverflow 和其他地方的文章,其中测试用于比较 Fork/Join 与 ExecutorService,并且有图表显示 Fork/Join 与 ExecutorService 更好的 CPU 使用率(通过 Windows 任务管理器)。但是,当我使用 ExecutorService (JDK 1.7.x) 时,我的 CPU 使用率最高。ExecutorService 是否使用最新的 JDK 进行了改进?

任何帮助/指导表示赞赏。

4

1 回答 1

4

您应该添加awaitTermination调用,因为shutDown无需等待 Callables 完成即可返回。除此之外,

  1. OuterCallable有顺序依赖吗?如果是这样,您的方法很好,但使用 ForkJoinPool 会更可取,因为它将保持工作线程的数量较少。如果没有,最好将一大堆扁平化的Callables 集合提交给单个 s Executor
  2. 仅当您想在几个不同的例程中使用 ExecutorService 并希望避免传递它时。如果它只在 中使用someMethod,不妨像你正在做的那样在那里实例化它。
  3. 您应该避免需要很长时间才能完成的 I/O 例程。如果您的 ExecutorService 有 4 个工作线程并且它们都在 I/O 上阻塞,则 JVM 根本不会使用 CPU,即使其他 Callables 可能正在等待执行 CPU 密集型工作。只要查询不需要很长时间即可完成,一些 JDBC 调用是可以的。
于 2012-02-27T13:22:28.317 回答