【问题标题】:TimeoutTask using ExecutorServiceTimeoutTask 使用 ExecutorService
【发布时间】:2015-06-06 00:17:47
【问题描述】:

我已经使用 ExecutorService 实现了一个 TimeoutTask。在下面的方法中,我提交了 TimeoutTask,如果它在给定时间内超时,我取消任务并关闭执行程序。

private boolean waitForProcessToBeCompleted(long timeOut) {
            boolean result = false;
            ExecutorService executor = Executors.newSingleThreadExecutor();
            // Create a FutureTask which will be run
            FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new TimeoutTask());
            executor.submit(futureTask); // Run the FutureTask
            try {
                result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                futureTask.cancel(true);
                result = true;  // Return True only when timed out
            } finally {
                executor.shutdownNow(); // Stop the executor
            }
            return result;
        }

它运行得很好,我没有任何问题。

但是,我想知道这是否是最好的代码设计。我只是想知道使用 ExecutorService.submit() 返回的 Future 来获取 Callable 的返回值或超时 TimeoutTask 是否会更好。例如

            Future<?> futureTask = executor.submit(new TimeoutTask()); // Run the FutureTask
            try {
                result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                futureTask.cancel(true);
                result = true;  // Return True only when timed out
            } finally {
                executor.shutdownNow(); // Stop the executor
            }
            return result;

我正在使用 JDK7。

【问题讨论】:

    标签: java concurrency


    【解决方案1】:

    我更喜欢使用CountDownLatch:

    List<List<String>> elements = MyPartition.partition(bigObjectList, size); 
    List<Future<?>> tasks = new ArrayList<Future<?>>();
    ExecutorService executor = Executors.newSingleThreadExecutor();
    CountDownLatch doneSignal =  new CountDownLatch(10);
    for(List<String> l: elements) {         
       ReadTask worker = new ReadTask(doneSignal, l);
       tasks.add(executor.submit(worker));
    }   
    
    long timeout = 10000;
    doneSignal.await(timeout, TimeUnit.SECONDS);
    boolean notFinished = false;
    if(doneSignal.getCount() > 0) {
      for(Future<?> fut : tasks) {
        if(!fut.isDone()) {
          System.out.println("Sub Thread " + fut + " has not finshed!");
          fut.cancel(true);             
          notFinished = true;
        }
      }
    }
    

    【讨论】:

      【解决方案2】:

      如果您查看futureTask.cancel 的代码,您会发现它只是试图中断正在执行任务的线程。如果任务规则检查中断标志,显式或隐式(通过调用 sleep() 或 wait()),此中断可能会起作用。在 Java 中,没有其他安全的方法可以停止方法的执行。

      因此,您可以实现相同的功能,而无需每次都创建单独的单线程执行器。相反,从 waitForProcessToBeCompleted 方法中执行 TimerTask。为了收到超时通知,请将监视任务提交给 SheduledExecutorService。监视任务应该中断执行 TimerTask 的线程。如果任务在超时之前完成,则取消正在观看的任务。

      这样您需要一个 SheduledExecutorService,但它消耗的处理器周期非常少,并且可以在整个应用程序中重复使用。

      【讨论】:

      • 谢谢阿列克谢。但是,在上面的代码设计中,我可以使用 submit() 返回的 Future 来获取结果,而不是使用单独的 FutureTask。这有意义吗?
      • 这没有意义,因为 submit(Callable) 返回的 Future 实际上是一个 FutureTask。有两种方法可以做到这一点。
      • 再次感谢。但我只是想知道我是否使用 submit() 返回的 Future 对象,我不需要显式声明它。我只是使用返回值。无论如何,谢谢。
      【解决方案3】:

      ExecutorService 上的invokeAll 方法可用于自动取消超过超时的任务。这使您可以在不关闭线程池的情况下取消任务(如果您愿意,您可以将相同的线程池重新用于其他事情)。

      private boolean waitForProcessToBeCompleted(long timeOut) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        List<FutureTask> tasks = new ArrayList<>();
        tasks.add(new SomeFutureTaskThing()));
        List<Future<Boolean>> results;
        try {
          results = executor.invokeAll(tasks, timeOut, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt(); // Restore interrupt status.
          return null;
        } catch (ExecutionException e) {
          throw new RuntimeException(e.getCause());
        }
        Future<Boolean> result = results.get(0);
        try {
          return result.get();
        } catch (CancellationException e) {
          System.err.println("Timed out");
          return null;
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多