同时使用Future.get()与executorService.awaitTermination,实际生效超时时间是多少?
关于Future.get()与executorService.awaitTermination超时的说明
首先纠正你代码里的一个关键错误:executorService.invokeAll(taskList)的返回值是List<Future<T>>,你直接调用tasksList.get(0).get()是错误的——因为tasksList存的是Callable对象,它没有get()方法,必须接收invokeAll返回的Future列表才能获取任务结果。
接下来解释两个超时的作用,它们针对完全不同的场景,不存在谁覆盖谁的“生效”问题:
1. Future.get(5, TimeUnit.MINUTES)的作用
这个超时是针对单个任务的结果获取等待:
- 如果你调用的是带超时的
invokeAll(比如invokeAll(tasks, timeout, unit)),未完成的任务会被取消,返回的Future可能处于未完成状态,此时调用get(5分钟)会等待该任务完成,最多等5分钟,超时则抛出TimeoutException。 - 但在你的代码里,用的是不带超时的
invokeAll(tasksList),这个方法会一直等待所有任务执行完成才返回,返回的每个Future都是已完成状态。所以后续的get(5分钟)会立刻返回结果,这个超时设置完全冗余,不会触发。
2. executorService.awaitTermination(30, TimeUnit.SECONDS)的作用
这个超时是针对线程池关闭后的终止等待:
- 调用
shutdown()后,线程池会拒绝新任务,但会等待已提交的任务全部执行完毕。awaitTermination则是等待线程池里的所有工作线程都终止(即线程池彻底关闭),最多等30秒。 - 但在你的代码逻辑里,
invokeAll已经等所有任务完成了,get也拿到了结果,此时线程池里已经没有正在运行的任务,调用awaitTermination会立刻返回true,30秒的超时同样不会触发。
正确的超时控制姿势
如果你想限制任务的执行总时长,应该直接使用invokeAll的带超时重载方法,比如:
ExecutorService executorService = executorServiceFactory.createThreads(2); List<Callable<T>> tasksList = new ArrayList<>(); tasksList.add(task1); tasksList.add(task2); // 控制所有任务在5分钟内完成,未完成的任务会被取消 List<Future<T>> futures = executorService.invokeAll(tasksList, 5, TimeUnit.MINUTES); // 遍历Future获取结果,注意处理可能的取消或异常 for (Future<T> future : futures) { if (future.isDone() && !future.isCancelled()) { T result = future.get(); // 处理结果 } } executorService.shutdown(); // 等待线程池关闭,这里的超时是给线程池清理留的时间,和任务执行无关 executorService.awaitTermination(30, TimeUnit.SECONDS);
总结:你代码里的两个超时都不会实际触发,因为它们的作用场景和你的代码逻辑不匹配——前者在任务已完成时冗余,后者在线程池无任务时无用。
内容的提问来源于stack exchange,提问作者Haobo_X
相关产品推荐
相关产品推荐

