6

我在一个模拟系统上工作,在每个时间步,我必须模拟许多模型。我使用了 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

4 回答 4

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
}

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

注意事项:我没有编译代码,所以可能会有错误。为了方便起见,我还假设了一个整数参数类型。

于 2012-01-27T16:03:25.177 回答
1

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

于 2012-01-27T16:07:43.507 回答
1

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

考虑到这shutdown()可能会进行大量清理和垃圾收集,尚不清楚为什么重新启动会比获取新的更好Executor,也许您应该查看有关使用暂停/恢复方法集扩展ThreadPoolExecutor而不是添加功能的教程取消关机。

于 2012-01-27T15:57:39.870 回答
0

只需获得另一个ExecutorService. 无论如何,开销是最小的。

如果你坚持复用同一个executor,你可以实现自己的barrier机制。提交新任务后,自动递增计数器。当任务完成时,自动递减计数器。在主线程中等到计数器为零。就像是:

// 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();
    }        
}
于 2012-01-27T15:58:56.377 回答