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