如何将可调用任务提交到ExecutorService超时

时间:2014-11-14 11:57:34

标签: java executorservice

我将可调用任务(使用 submit())提交给 ExecutionService 的实施。偶尔我似乎遇到了死锁,但无法在哪里或为什么会发生这种情况,所以我想在任务上设置超时,我不清楚它是怎么做的?

我应该

  1. 在提交任务并设置超时时,在ExecutionService上使用 invokeAny()而不是 submit()。我使用submit()一次一个地提交许多任务,我是否可以像这样使用invokeAny(),我很谨慎,因为我无法理解为什么没有一个超时的submit()方法。 / LI>
  2. 在我的ExecutorService的构造函数中修改 keepAliveTime (但我认为这是在做其他事情
  3. 修改我的实际Callable实现,但如果它是死锁的,则无法自行解锁。
  4. 选项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()时它只会返回它没有进一步处理的任何方式,但有两个问题:

    1. 每个ExecutorService使用一个500的有界队列,这个想法是如果P2比P1慢得多,我们就不会将内容堆叠到ES2上并最终耗尽内存。所以现在P1没有完成,直到他们调用的任务完成后,队列实际上更小,因为它们不仅包括等待ES2上的插槽完成的任务,而且它们包含已经提交给ES2但正在等待它的任务光洁度。

    2. 管道是链接的,所以如果我们在从P1提交的任务上使用invokeAny,从P2和P3和P4提交任务,那么当任务从P1提交到P2时,它将不会返回,直到后续处理从E4完成!

5 个答案:

答案 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)

不确定这是否会对您有所帮助,但我在使用此配方之前设法快速轻松地找到了死锁:

  • 在eclipse中调试
  • 重现“挂”
  • 选择服务器实例,然后单击Eclipse调试器中的“暂停”按钮。这将暂停所有线程。
  • 现在向下滚动主题列表。死锁线程标记为红色。每个线程显示它持有的锁和它正在等待的锁。
  • 利润!

答案 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?