我将可调用任务(使用 submit())提交给 ExecutionService 的实施。偶尔我似乎遇到了死锁,但无法在哪里或为什么会发生这种情况,所以我想在任务上设置超时,我不清楚它是怎么做的?
我应该
选项1似乎是唯一可行的解决方案,但是它呢?
更多详情
我认为如果有助于解决方案,可能需要更详细地解释该流程的工作原理。
可调用任务P1启动并处理文件夹及其中的所有文件和文件夹,并开始将歌曲分组,在ExecutorService ES1中运行,只有一个P1实例提交给ES1。 / p>
我们还有三个其他可调用类:P2,P3和P4 - 每个类都有自己的相关Executor服务,ES2,ES3,Es4)。一旦P1创建了一个组,它就会将一个任务提交给相关的ES,并将该组作为数据传递,即它可以将一个P2实例提交给E2,P3或者提交给P3或P4提交给E4,它选择哪一个取决于详细信息。分组,P2,P3和P4都做不同的事情。
假设已提交P2的实例,P2将通过将P3提交到E3或P4提交到E4来完成处理。它的单向管道P3只能提交给P4,一旦所有任务都提交给P4,P4完成了处理完成的所有任务。
我们通过构建ES1,ES2,ES3和ES4完成处理,将任务提交给P1,然后依次调用每个ExecutorService上的shutdown(),这样,在P1完成提交所有组之后,shutdown()将不会返回,然后调用ES2上的shutdown(),直到ES2清除了P2任务的队列,才会返回。
非常偶然一切都停止我假设某些进程阻止其他进程继续进行,所以此时我想要一种取消进程的方法,这些进程需要太长时间,以便其他进程可以继续,这远远不如它只是无限地挂起< / p>
答案更新
我尝试按照建议使用invokeAny(),它有点工作。 如果P1将一个P2实例提交给E2,那么它在完成之前就会等待,这是好的,因为当使用submit()时它只会返回它没有进一步处理的任何方式,但有两个问题:
每个ExecutorService使用一个500的有界队列,这个想法是如果P2比P1慢得多,我们就不会将内容堆叠到ES2上并最终耗尽内存。所以现在P1没有完成,直到他们调用的任务完成后,队列实际上更小,因为它们不仅包括等待ES2上的插槽完成的任务,而且它们包含已经提交给ES2但正在等待它的任务光洁度。
管道是链接的,所以如果我们在从P1提交的任务上使用invokeAny,从P2和P3和P4提交任务,那么当任务从P1提交到P2时,它将不会返回,直到后续处理从E4完成!
答案 0 :(得分:4)
您可以使用番石榴MoreExecutors
ListeningExecutorService
。它不会神奇地解决你的问题,但可以提供一些帮助:
1)您可以通过Callable
为每个invokeAll
设置超时。如果在给定时间内没有完成可调用,则应该将其杀死。
2)您可以创建所有ListenableFuture
的全局映射,其中每个映射都会在创建时注册一个标志,并在完成时清除该标志。通过这种方式,您可以知道哪些未来未能帮助缩小问题范围。
答案 1 :(得分:2)
我认为最好的方法是找到并修复死锁。你不能只是杀死线程。您应该在任务中实现某种任务取消,并请求此任务取消它正在执行的操作。但如果它陷入僵局,你就无法做任何事情。You can use jsconsole to detect a deadlock
使用带有超时的invokeAny阻塞线程,直到其中一个提交的任务成功完成或超时到期。如果超时到期,您将获得TimeoutException,但您的任务将运行。 ExecutorService将要求他们使用Future.cancel取消(true)。在内部它会中断线程,将任务的线程isInterrupted标志设置为true。如果您在任务中使用阻塞方法(响应中断),它们将抛出中断异常。否则,您应检查任务中的中断状态,如果返回true,则相应地响应。如果没有阻止方法或检查中断状态,则此取消将不起作用。
答案 2 :(得分:0)
不确定这是否会对您有所帮助,但我在使用此配方之前设法快速轻松地找到了死锁:
答案 3 :(得分:0)
始终建议修复死锁情况。但是为了做出替代,您可以使用未来的callable对象来设置超时持续时间。
签出单个可调用实例的解决方案。同样,您可以使用List of Future调用实现可调用的数量。它使用future.get(...)方法,我们设置超时。如果可调用没有按设置的超时完成执行,则线程将完成其执行。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ThreadTimeOut{
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Task());
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
class Task implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
return "Ready!";
}
}
答案 4 :(得分:0)
@PhilipWhitehouse的评论在我做了一些修改之后就起作用了。
总之,创建一个自定义ThreadPool,用于封装ScheduledExecutorPool,以便在提交任务时设置超时。
完全解决方案:
How can I make shutdown work properly with this custom ExecutorService?