java重用执行器

java重用执行器,java,multithreading,concurrent-programming,java.util.concurrent,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,

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

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

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


考虑到
shutdown()
可能会进行大量清理和垃圾收集,现在还不清楚为什么重新启动会比使用新的
执行器更好,也许您应该查看教程,而不是添加取消关机的功能。

只需获取另一个
执行器服务即可。无论如何,开销是最小的

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

// 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();
   }
}
然后在任务的
运行

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

如果稍微重新构造代码,则可以重用executor服务

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
}
Collection tasks=newarraylist(16);
适用于(型号m:型号){
tasks.add(m.simulationTask());
}
ExecutorService executor=Executors.newFixedThreadPool(nThread);
试一试{
执行人。调用所有(任务);
}捕获(中断异常ie){
//处理这个
}
基本上,您收集所有任务,执行它们,并在继续之前等待执行。当然,您也可以为每个时间步使用新的Executor服务,但至少您有选择


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

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

我不会说创建一个线程池支持的执行器的开销最小……这取决于他使用了多少线程。如果这个数字很小,那么就没有多少开销。此外,如果他正在执行的任务是粗粒度的,那么相对于应用程序的其余部分来说,它是可以忽略不计的。在进入下一步之前,您还没有演示如何等待所有任务完成。@dogbane-
invokeAll
等待所有任务完成。因为他正在使用
execute(Runnable)
它不返回值,我们可以选择
可调用的
也许?@mzzzzb-我通常喜欢假设某种返回类型,但是的,他肯定可以。