首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Java中,当executorservice可能向自己提交额外任务时,如何关闭executorservice

在Java中,当executorservice可能向自己提交额外任务时,如何关闭executorservice
EN

Stack Overflow用户
提问于 2012-06-08 11:32:02
回答 5查看 4.8K关注 0票数 2

我有一个任务管道(流水线中的每个任务都有不同的并行性要求),每个任务在不同的ExecutorService中工作。任务工作在数据包上,所以如果我们有10个数据包,那么10个任务将提交给service1,每个数据包一个任务。一旦提交给service1的任务实际调用了,它就可能提交一个新的任务来进一步处理service2service3的数据集。

以下代码运行良好,即:

  • 在将所有内容提交给shutdown()后,在service1上调用service1
  • 在关闭()之前提交的所有任务实际运行完毕后,awaitTermination()才会返回。--然后在shutdown()上调用service2,但是因为提交给service1的所有任务都已经完成,所有任务都是从service1上的任务提交给service2的,所以在shutdown()被调用到service2之前,所有任务都被提交给了service2。- service3等等 ExecutorService[]服务={ service1,service2,service3};int count = 0;for(ExecutorService服务: services) { service.shutdown();service.awaitTermination(1,TimeUnit.HOURS);}

不过,我现在添加了一种情况,即service2可以将数据分组分解为更小的数据包,并在service2上提交附加任务,而代码现在正在失败。问题是,一旦shutdown()上的所有任务都完成了,就会在service2上调用service2,但是现在我们想从运行在service2中的任务中提交额外的service2任务

我的问题:

  1. 在所有提交的任务运行完毕后,shutdown()是否重新运行,还是会立即返回,但不会停止已提交的任务运行?更新:在下面回答
  2. 我该如何解决我的新问题?
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-06-08 14:10:13

Matts的问题看上去可能很有效,但我担心它可能会引发新的问题。

我已经想出了一种解决方案,虽然它看起来有点笨重,但在我的场景中没有很多代码更改就能工作。

我引入了一个新服务(service2a),它运行与service2相同的任务。当service2中的任务想要提交一个小数据包时,它会将它提交给service2a而不是service2,因此在服务2关闭之前,所有子数据包都会提交给service2a。这对我来说是有效的,因为较小的数据包不需要被分解成更多的子包,子数据包的想法只适用于service2(a),而不适用于任何其他服务。

票数 0
EN

Stack Overflow用户

发布于 2012-06-08 13:40:05

“关机”只是告诉池不要接受更多的工作。它只会起作用。所有现有提交的工作将按正常方式执行。当队列耗尽时,池实际上将销毁它的所有线程并终止。

这里的问题是,您说service2中的任务将向service2提交其他任务以供处理。似乎没有办法知道什么时候你真的应该叫关机。但遗憾的是,假设这些较小的数据包不会进一步分解为服务,还有一种选择。

代码语言:javascript
运行
复制
List<Future<Void>> service2Futures = new ArrayList<Future<Void>>();

service2Futures.add(service2.submit(new Callable<Void>() {
  public Void call() throws Exception {
    // do your work, submit more stuff to service2
    // if you submit Callables, you could use Future.get() to wait on those
    // results.
    return null;
  }
}));

for (Future<Void> future : service2Futures) {
  future.get();
}

service2.shutdown();
...

这里要做的是存储顶级提交任务的未来对象(您必须使用可调用的,而不是可运行的)。而不是在提交后立即关闭池,您只需收集未来的对象。然后,通过循环遍历它们,然后调用get(),直到它们全部运行完毕。"get()“方法会阻塞,直到运行该任务的线程完成为止。

此时,所有顶级任务都已完成,它们将提交第二级任务。现在可以发出关机了。这假设第二级任务不会向service2提交更多的东西。

尽管如此,如果您使用的是java 7,则应该考虑使用ForkJoinPool和RecursiveTask。对你所做的可能更有意义。

代码语言:javascript
运行
复制
ForkJoinPool forkJoinPool = new ForkJoinPool();
RecursiveAction action = new RecursiveAction() {
    protected void compute() {
         // break down here and build actions
         RecursiveAction smallerActions[] = ...; 
         invokeAll(smallerActions);
    }
};

Future<Void> future = forkJoinPool.submit(action);
票数 2
EN

Stack Overflow用户

发布于 2012-06-08 12:05:24

ExecutorService#shutdown让已经提交的任务完成他们正在做的事情- javadoc提取物

启动有序关机,执行以前提交的任务,但不接受任何新任务。如果已经关闭,则调用没有其他效果。 此方法不等待以前提交的任务完成执行。使用awaitTermination来完成这个任务。

在实践中,您可以考虑调用shutdown可以执行以下几项任务:

  1. ExecutorService再也不能接受新的工作了
  2. 现有线程一旦完成运行,就会终止。

因此,要回答你的问题:

  • 如果您在调用service1之前向service1.shutdown提交了所有任务(如果在调用之后提交任何内容,您将得到一个异常),则可以(即,如果这些任务向service2提交了一些东西,而service2没有关闭,那么它们将被执行)。
  • 关机立即返回,并不保证已经提交的任务将停止(它们可能永远运行)。
  • 您所遇到的问题可能与您如何将任务从一项服务提交到另一项服务有关,而且似乎很难仅用您所提供的信息来解决它。

最好的方法是在你的问题中加入一个复制你所看到的行为的SSCCE

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10948024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档