跳转到主内容
极星编程网:以代码为星,赴技术山海!

Future与Callable接口应用_如何获取多线程任务的执行结果

Future.get() 默认阻塞,易卡住,须设超时;Callable 才能返回结果,Runnable 的 get() 恒为 null;批量任务用 invokeAll() 或 CompletableFuture.allOf();Future 必须显式持有,否则结果可能被 GC 回收。 Future.get() 为什么经常卡住? 因为
get()
默认阻塞等待结果,线程没结束就一直挂起。常见于任务耗时长、未设超时、或任务本身抛异常没被捕获。 务必搭配超时参数使用:
future.get(5, TimeUnit.SECONDS)
,避免无限等待 捕获
ExecutionException
(包装了任务内抛出的异常)和
TimeoutException
,别只写
Exception
如果任务已取消,
get()
会直接抛
CancellationException
,需单独处理 注意:调用
get()
前最好先用
isDone()
或
isCancelled()
做轻量判断,减少不必要的阻塞尝试 Callable 和 Runnable 在 submit() 里怎么选? 关键看要不要返回值。用
Runnable
提交的任务,
submit()
返回的
Future>
的
get()
永远是
null
;而
Callable
才能真正传递计算结果。
ExecutorService.submit(Runnable)
→ 返回
Future>
,
get()
只能确认是否完成,无法获取业务数据
ExecutorService.submit(Callable)
→ 返回
Future
,
get()
返回你
call()
方法里 return 的值 别为了“看起来像有返回”硬套
Runnable
+ 成员变量收集结果——这破坏线程安全,且无法通过
Future
统一管理生命周期 批量提交 Callable 任务后,怎么安全等全部结果? 别用循环调
get()
等前一个再启下一个——这等于串行执行。要用
invokeAll()
或异步轮询 + 超时控制。
executor.invokeAll(callableList)
会阻塞直到所有任务完成(或超时),返回
List>
,每个元素对应一个任务的结果 若需更细粒度控制(比如某个失败不影响其余),改用
submit()
批量提交,再用
CompletableFuture.allOf()
(Java 8+)组合,或手动遍历检查
isDone()
注意
invokeAll()
的超时是“整体超时”,不是单个任务超时;若某任务卡死,整个调用仍会等到超时才返回 返回的
Future
列表顺序与提交顺序一致,可直接按索引取结果,无需额外 map 关联 Future 的结果丢了?可能是被 GC 回收了
Future
对象本身不持有任务引用,一旦你没把
Future
实例存住,又没调
get()
,JVM 可能在任务完成后就回收它——后续再想取结果就只能得到
CancellationException
或空指针。 必须将
Future
存为局部变量、成员变量,或放进集合里长期持有,直到你明确不需要结果为止 别写这种代码:
executor.submit(() -> doWork()).get();
——
Future
是临时对象,GC 可能介入,行为不可靠 如果任务逻辑复杂、可能失败,建议在
call()
内部做日志或状态标记,不能只依赖外部
Future
的存在来判断执行情况 事情说清了就结束

相关文章