java重用执行器

时间:2012-01-27 15:51:37

标签: java multithreading concurrent-programming java.util.concurrent

我在模拟系统上工作,在每个时间步,我必须模拟许多模型。我使用FixedThreadPool来加速计算:

ExecutorService executor = Executors.newFixedThreadPool(nThread);
for (Model m : models) {
  executor.execute( m.simulationTask() );
}
executor.shutdown();
while ( ! executor.awaitTermination(10, TimeUnit.MINUTES) ) { 
  System.out.println("wait"); 
}

现在,在调用execute()后,执行程序无法用于shutdown()个新任务。有没有办法重置执行程序,所以我可以在下一个模拟步骤中重用现有的执行程序(及其线程)?

4 个答案:

答案 0 :(得分:7)

如果稍微重构代码,可以重用执行程序服务。

Collection<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>(16);
for (Model m : models) {
  tasks.add(m.simulationTask());
}

ExecutorService executor = Executors.newFixedThreadPool(nThread);
try {
  executor.invokeAll(tasks);
} catch(InterruptedException ie) {
  // Handle this
}

基本上,您在继续之前收集所有任务,执行它们并等待执行。当然,您也可以为每个时间步骤使用新的Executor服务,但至少可以选择。

警告 :我没有编译代码,因此可能存在错误。为方便起见,我还假设了一个Integer参数类型。

答案 1 :(得分:1)

您可以编写自己的Executor接口实现。除此之外,我所知道的大多数默认实现都会在shutdown()之后获取线程并进行内存清理,因此没有(据我所知)预先制定的解决方案。

考虑到shutdown()可能会进行大量的清理和垃圾收集,但是为什么重新启动比获取新的Executor更好还不清楚,或许你应该查看教程{{ 3}}而不是添加取消关闭的能力。

答案 2 :(得分:1)

将您的ExecutorService声明为您班级的成员,并根据需要重复使用。不要在它上面调用shutDown(),因为它不会再接受任何任务。当然,你的任务应该很好地结束,它们也应该在某个时候终止。

答案 3 :(得分:0)

获得另一个ExecutorService。无论如何,开销很小。

如果您坚持重用相同的执行程序,则可以实现自己的屏障机制。提交新任务后,以原子方式递增计数器。当任务完成时,原子地减少计数器。在主线程中等待计数器为零。类似的东西:

// globally visible objects
AtomicInteger counter = new AtomicInteger(0);
Object signal = new Object();

ExecutorService executor = Executors.newFixedThreadPool(nThread);
for (Model m : models) {
  counter.getAndIncrement();
  executor.execute( m.simulationTask() );
}

synchronized(signal) {
   while(count.get() > 0) {
       signal.wait();
   }
}

然后在你的任务run内:

public void run() {
    // original code
    // at the end:
    synchronized(signal) {
       counter.getAndDecrement();
       signal.notify();
    }        
}