返回 导航

其他

hangge.com

Java - 3种方式实现任务执行超时自动取消功能(限制方法执行时间)

作者:hangge | 2022-12-20 08:10
    当我们程序在处理长时间运行的任务时(例如网络连接或计算密集型任务时),通常需要设置超时时间,避免由于资源被长时间占用而影响系统其他功能的正常执行。Java 中有多个方式可以实现该功能需求,假设我们有一个如下耗时方法,每隔 1 秒打印一段信息,总共持续 10 秒:
// 耗时的方法
public static Object longRunningMethod() {
  for (int i = 0; i < 10; i++) {
    System.out.println("这是第" + (i + 1) + "次打印");
    try {
      //等待1秒
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
      return null;
    }
  }
  return "完成";
}
下面分别使用 3 种方式来实现任务超时取消功能。 

1,使用线程池和 Future 实现

(1)该方法是通过基于异步任务结果的获取来实现的,具体流程如下:
  • 首先创建了一个新的线程池 executor 和一个新的 CompletionService,用于监控要限制时间的方法的执行情况。
  • 然后,我们使用 completionService.submit() 方法提交要执行的方法,该方法会返回一个 Future 对象。
  • 接着使用 completionService.poll() 方法来获取执行结果。如果该方法在超时时间内执行完毕,则会返回执行结果,我们可以对执行结果进行处理;如果该方法超时了,可以调用 Future 对象的 cancel() 方法来取消任务。
(2)样例代码如下:
public class Test {
  public static void main(String[] args) {
    // 定义超时时间为3秒
    long timeout = 3000;
    // 创建一个新的线程池,用于执行要限制时间的方法
    Executor executor = Executors.newSingleThreadExecutor();

    // 创建一个新的CompletionService,用于监控执行时间
    CompletionService<Object> completionService = new ExecutorCompletionService<>(executor);

    // 提交要执行的方法
    Future<?> future = completionService.submit(new Callable<Object>() {
      public Object call() throws Exception {
        // 这里是要执行的方法
        return longRunningMethod();
      }
    });

    // 获取执行结果
    try {
      Object result = completionService.poll(timeout, TimeUnit.MILLISECONDS);
      if (result == null) {
        System.out.println("超时了,结束该方法的执行");
        future.cancel(true);
      } else {
        // 方法执行完毕,处理执行结果
        System.out.println("方法执行完毕,结果:" + result.toString());
      }
    } catch (InterruptedException e) {
      System.out.println("出现异常,结束该方法的执行");
      future.cancel(true);
    }
  }
}

2,使用 FutureTask 实现

(1)我们还可以使用 Java 5 新增的 java.util.concurrent.FutureTask 类来限制方法的执行时间,具体流程如下:
  • 首先创建了一个 FutureTask 对象,用于监控要限制时间的方法的执行情况。
  • 然后使用 new Thread(futureTask).start() 方法在新线程中执行要限制时间的方法,并使用 futureTask.get() 方法来获取执行结果。如果该方法在超时时间内执行完毕,则会返回执行结果。如果该方法超时了,则会抛出异常,我们在异常处理中调用 futureTask.cancel() 方法取消任务。
(2)样例代码如下:
public class Test {
  public static void main(String[] args) {
    // 定义超时时间为3秒
    long timeout = 3000;

    // 创建一个新的FutureTask
    FutureTask<Object> futureTask = new FutureTask<Object>(new Callable<Object>() {
      public Object call() throws Exception {
        // 这里是要执行的方法
        return longRunningMethod();
      }
    });

    // 提交要执行的方法
    new Thread(futureTask).start();

    // 获取执行结果
    try {
      Object result = futureTask.get(timeout, TimeUnit.MILLISECONDS);
      System.out.println("方法执行完毕,结果:" + result.toString());
    } catch (InterruptedException e) {
      System.out.println("出现异常,结束该方法的执行");
      futureTask.cancel(true);
    } catch (ExecutionException e) {
      System.out.println("出现异常,结束该方法的执行");
      futureTask.cancel(true);
    } catch (TimeoutException e) {
      // 超时了,结束该方法的执行
      System.out.println("超时了,结束该方法的执行");
      futureTask.cancel(true);
    }
  }
}

3,使用 CompletableFuture 实现

(1)最简单的方法还是使用 Java 8 新增的 java.util.concurrent.CompletableFuture 类来限制方法的执行时间,具体流程如下:
  • 首先创建了一个 CompletableFuture 对象,用于监控要限制时间的方法的执行情况。
  • 然后,我们使用 CompletableFuture.supplyAsync() 方法提交要执行的方法,并使用 future.get() 方法来获取执行结果。如果该方法在超时时间内执行完毕,则会返回执行结果。如果该方法超时了,则会抛出异常,我们在异常处理中调用 future.cancel() 方法取消任务。
(2)样例代码如下:
public class Test {
  public static void main(String[] args) {
    // 定义超时时间为3秒
    long timeout = 3000;

    // 创建一个新的CompletableFuture
    CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
      // 这里是要执行的方法
      return longRunningMethod();
    });

    // 获取执行结果
    try {
      Object result = future.get(timeout, TimeUnit.MILLISECONDS);
      System.out.println("方法执行完毕,结果:" + result.toString());
    } catch (InterruptedException e) {
      System.out.println("出现异常,结束该方法的执行");
      future.cancel(true);
    } catch (ExecutionException e) {
      System.out.println("出现异常,结束该方法的执行");
      future.cancel(true);
    } catch (TimeoutException e) {
      // 超时了,结束该方法的执行
      System.out.println("超时了,结束该方法的执行");
      future.cancel(true);
    }
  }
}
评论

全部评论(0)

回到顶部