【问题标题】:Time limit on individual threads with ExecutorServiceExecutorService 对单个线程的时间限制
【发布时间】:2011-06-16 17:34:28
【问题描述】:

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

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

【问题讨论】:

    标签: java multithreading threadpool


    【解决方案1】:

    当达到超时时,使用 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;
    }
    

    【讨论】:

    • 最好使用Runnable 而不是Callable - 减少返回类型的混乱,无需返回任何内容。
    • 或者在 Java 8 中,您可以将那么长的 canceller.schedule(...) 缩短为 canceller.schedule(() -&gt; future.cancel(true), timeoutMS, TimeUnit. MILLI_SECONDS);
    【解决方案2】:

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

    【讨论】:

    • +1 指出该任务可能需要一些智能。
    【解决方案3】:

    您最好的方法是再引入一位 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);
    }
    

    【讨论】:

    • 调用需要返回值。
    • 谢谢,你可以想象我只是徒手写的。要是 Firefox 有内置编译器就好了:)
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      你可以用这个方法

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

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

      【讨论】:

        猜你喜欢
        • 2019-03-15
        • 2020-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-01
        • 2019-04-11
        • 2015-12-06
        • 1970-01-01
        相关资源
        最近更新 更多