java 重用执行器

发布于 2024-12-29 06:15:55 字数 443 浏览 2 评论 0原文

我研究一个模拟系统,在每个时间步,我必须模拟许多模型。我使用了固定线程池来加速计算:

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() 新任务。有没有办法重置执行器,以便我可以在下一个模拟步骤中重用现有的执行器(及其线程)?

I work on a simulation system, where at each timestep, I have to simulate many models. I used a FixedThreadPool to speed up the calculation:

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"); 
}

Now, the executor can't be used to execute() new Tasks after calling shutdown(). Is there a way to reset the executor, so I can reuse the existing executor (and its threads) at the next simulation step?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

口干舌燥 2025-01-05 06:15:55

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

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
}

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

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

You can reuse the executor service if you restructure your code somewhat.

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
}

Basically you collect all your tasks, execute them, and await execution before proceeding. Of course, you could also alternatively just use a new Executor Service for each of your time steps, but at least you have options.

Caveats: I didn't compile the code so there might be errors. I also assumed an Integer parameter type for convenience.

塔塔猫 2025-01-05 06:15:55

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

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

You can write your own implementation of the Executor interface. Beyond that, most of the default implementation that I am aware of reap threads and do memory cleanup after shutdown(), so there is no (to my knowledge) pre-made solution.

Considering that shutdown() is likely to do a lot of cleanup and garbage collection, it's not exactly clear why restarting would be better than accquiring a new Executor, perhaps you should look into the tutorials about extending ThreadPoolExecutor with a pause / resume set of methods instead of adding the ability to un-shutdown.

北座城市 2025-01-05 06:15:55

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

Declare your ExecutorService as a member to your class and reuse it as you want. Do not call shutDown() on it as it will not accept any more tasks. Of course your tasks should end nicely and they also should terminate at some point.

花开半夏魅人心 2025-01-05 06:15:55

只需获取另一个 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();
    }        
}

Just acquire another ExecutorService. The overhead is minimal anyway.

If you insist on reusing the same executor, you can implement your own barrier mechanism. Upon submitting a new task, atomically increment a counter. When a task finishes, atomically decrement the counter. In the main thread wait until the counter is zero. Something like:

// 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();
   }
}

Then inside the run of your tasks:

public void run() {
    // original code
    // at the end:
    synchronized(signal) {
       counter.getAndDecrement();
       signal.notify();
    }        
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文