我在模拟系统上工作,在每个时间步,我必须模拟许多模型。我使用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()
个新任务。有没有办法重置执行程序,所以我可以在下一个模拟步骤中重用现有的执行程序(及其线程)?
答案 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();
}
}