我有一个任务管道(流水线中的每个任务都有不同的并行性要求),每个任务在不同的ExecutorService中工作。任务工作在数据包上,所以如果我们有10个数据包,那么10个任务将提交给service1,每个数据包一个任务。一旦提交给service1的任务实际调用了,它就可能提交一个新的任务来进一步处理service2、service3的数据集。
以下代码运行良好,即:
shutdown()后,在service1上调用service1shutdown()上调用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任务
我的问题:
shutdown()是否重新运行,还是会立即返回,但不会停止已提交的任务运行?更新:在下面回答发布于 2012-06-08 14:10:13
Matts的问题看上去可能很有效,但我担心它可能会引发新的问题。
我已经想出了一种解决方案,虽然它看起来有点笨重,但在我的场景中没有很多代码更改就能工作。
我引入了一个新服务(service2a),它运行与service2相同的任务。当service2中的任务想要提交一个小数据包时,它会将它提交给service2a而不是service2,因此在服务2关闭之前,所有子数据包都会提交给service2a。这对我来说是有效的,因为较小的数据包不需要被分解成更多的子包,子数据包的想法只适用于service2(a),而不适用于任何其他服务。
发布于 2012-06-08 13:40:05
“关机”只是告诉池不要接受更多的工作。它只会起作用。所有现有提交的工作将按正常方式执行。当队列耗尽时,池实际上将销毁它的所有线程并终止。
这里的问题是,您说service2中的任务将向service2提交其他任务以供处理。似乎没有办法知道什么时候你真的应该叫关机。但遗憾的是,假设这些较小的数据包不会进一步分解为服务,还有一种选择。
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。对你所做的可能更有意义。
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);发布于 2012-06-08 12:05:24
ExecutorService#shutdown让已经提交的任务完成他们正在做的事情- javadoc提取物
启动有序关机,执行以前提交的任务,但不接受任何新任务。如果已经关闭,则调用没有其他效果。 此方法不等待以前提交的任务完成执行。使用awaitTermination来完成这个任务。
在实践中,您可以考虑调用shutdown可以执行以下几项任务:
ExecutorService再也不能接受新的工作了因此,要回答你的问题:
service1之前向service1.shutdown提交了所有任务(如果在调用之后提交任何内容,您将得到一个异常),则可以(即,如果这些任务向service2提交了一些东西,而service2没有关闭,那么它们将被执行)。最好的方法是在你的问题中加入一个复制你所看到的行为的SSCCE。
https://stackoverflow.com/questions/10948024
复制相似问题