ExecutorService 对单个线程的时间限制

发布于 2024-10-14 18:40:04 字数 181 浏览 5 评论 0原文

我有一个 ExecutorService 管理许多 Callables。 Callables 运行的任务主要是黑盒转换和数字运算。在某些情况下,正在转换的数据会振荡,线程将需要一个多小时才能完成。相比之下,大多数线程在一分钟内完成。

已确定来自长时间运行的线程的数据不相关。我想中断任何运行时间超过一定时间的线程。最好的方法是什么?

I have an ExecutorService managing a number of Callables. The tasks that the Callables run are mostly black box transformations and number crunching. Under certain conditions, the data being transformed will oscillate and the thread will take over an hour to finish. For comparison, most threads are completed within a minute.

It's been deteremined that the data from the long-running threads is not relevent. I would like to interrupt any thread that runs longer than a certain amount of time. What would the best way to do this?

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

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

发布评论

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

评论(6

水晶透心 2024-10-21 18:40:04

使用 ScheduleExecutorService 在达到超时时将任务安排到 taskFuture.cancel(true) 长时间运行的任务。如果任务在此之前完成,则不会被取消。

ExecutorService service = Executors.newFixedThreadPool(N);
ScheduledExecutorService canceller = Executors.newSingleThreadScheduledExecutor();

public <T> Future<T> executeTask(Callable<T> c, long timeoutMS){
   final Future<T> future = service.submit(c);
   canceller.schedule(new Callable<Void>(){
       public Void call(){
          future.cancel(true);
          return null;
       }
    }, timeoutMS, TimeUnit.MILLI_SECONDS);
   return future;
}

Use a ScheduleExecutorService to schedule a task to taskFuture.cancel(true) the long running task when the timeout is reached. If the task finishes before then it won't be cancelled.

ExecutorService service = Executors.newFixedThreadPool(N);
ScheduledExecutorService canceller = Executors.newSingleThreadScheduledExecutor();

public <T> Future<T> executeTask(Callable<T> c, long timeoutMS){
   final Future<T> future = service.submit(c);
   canceller.schedule(new Callable<Void>(){
       public Void call(){
          future.cancel(true);
          return null;
       }
    }, timeoutMS, TimeUnit.MILLI_SECONDS);
   return future;
}
苹果你个爱泡泡 2024-10-21 18:40:04

您可以像其他答案中那样取消未来等,但您需要确保“数字运算”的线程可以处理中断并优雅地终止。你说这是一个黑匣子操作 - 你有多确定线程的中断状态正在黑匣子内被主动检查?如果不是,则无法通过中断取消它。编写黑匣子时需要考虑到中断。

You could cancel the future etc as in the other answers, but you need to make sure that your threads which are "number crunching" can handle the interrupt and terminate gracefully. You say that this a black box operation - how certain are you that the interrupted status of the thread is being checked actively within the black box? If it isn't, you can't cancel it with an interrupt. The black box needs to be written with interruption in mind.

放肆 2024-10-21 18:40:04

做到这一点的最佳方法是再引入一个 Executor。您可以使用 ScheduledExecutorService 取消所有长时间运行的任务,例如:

ExecutorService service = Executors.newFixedThreadPool(N);

ScheduledExecutorService canceller = Executors.newScheduledThreadPool(1);

public void executeTask(Callable<?> c){
   final Future<?> future = service.submit(c);
   canceller.schedule(new Runnable(){
       public void run(){
          future.cancel(true);
       }
    }, SECONDS_UNTIL_TIMEOUT, TimeUnit.SECONDS);
}

The best way for you to do this would be to introduce one more Executor. You can use a ScheduledExecutorService to cancel all long running tasks for example:

ExecutorService service = Executors.newFixedThreadPool(N);

ScheduledExecutorService canceller = Executors.newScheduledThreadPool(1);

public void executeTask(Callable<?> c){
   final Future<?> future = service.submit(c);
   canceller.schedule(new Runnable(){
       public void run(){
          future.cancel(true);
       }
    }, SECONDS_UNTIL_TIMEOUT, TimeUnit.SECONDS);
}
只有影子陪我不离不弃 2024-10-21 18:40:04

您可以获得相应 Futures 的列表(在您提交 Callable 时创建)及其启动时间。

然后,另一个任务可以每分钟检查是否有某个任务运行超过定义的时间,如果是,则在 Future 中调用 cancel(true) 。已完成的期货将从清单中删除。

You could get a list of your corresponding Futures (that are created when you submit a Callable) together with its startup time.

Another task could then check every minute if there are some task running for more than a defined time and if so, invoke cancel(true) in the Future. Done futures would be removed off the list.

゛时过境迁 2024-10-21 18:40:04

您可以使用此方法

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                              long timeout,
                              TimeUnit unit)
                          throws InterruptedException

并将最大超时设置为一分钟。如果你的线程花费的时间超过这个时间,它就会被中止。

You can use this method

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                              long timeout,
                              TimeUnit unit)
                          throws InterruptedException

and set the maximum timeout to one minute. If your thread takes more than that it is just aborted.

酒解孤独 2024-10-21 18:40:04

问题是你不能杀死/停止/挂起java线程。
全部已弃用。

future.cancel 只会在工作线程之前考虑,

因此如果线程被任何代码执行卡住并且没有考虑线程中断的逻辑,那么执行仍然会继续。

对于 executorService.shutdown(); 来说更是如此。

文档说。

除了尽力尝试停止处理之外,没有任何保证
积极执行任务。例如,典型的实现将
通过线程取消。中断,因此任何未能响应的任务
中断可能永远不会终止。

因此,唯一的解决方案是记录这种情况并解决固有问题。

    Future<?> future = executor.submit(task);
    try {
        future.get(15, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        // retry waiting. iterative approach not shown here
    } catch (ExecutionException e) {
        // your task exploded
    } catch (TimeoutException e) {
        // The task is running longer than usual
        // Log it for future analysis

        //If the interrupt signal is handled 
        //OR the task is stuck in the queue itself for a long time
        //then worth calling below 
        future.cancel(true);
    } 

The problem is you can not kill/stop/suspend the java thread.
All are deprecated.

future.cancel will only considered before worker thread

So if the thread is stuck with any code execution and doesn't have the logic to consider the thread interruption, then execution will still continue.

This is even true for executorService.shutdown();.

The documentation says.

There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks. For example, typical implementations will
cancel via Thread. interrupt, so any task that fails to respond to
interrupts may never terminate.

So the only solution is to log such a situation and fix the inherent issue.

    Future<?> future = executor.submit(task);
    try {
        future.get(15, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        // retry waiting. iterative approach not shown here
    } catch (ExecutionException e) {
        // your task exploded
    } catch (TimeoutException e) {
        // The task is running longer than usual
        // Log it for future analysis

        //If the interrupt signal is handled 
        //OR the task is stuck in the queue itself for a long time
        //then worth calling below 
        future.cancel(true);
    } 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文