Future
1.Future类有什么用?
Future
类是异步思想的典型运用,主要用在一些需要执行耗时任务的场景,避免程序一直原地等待耗时任务执行完成,执行效率太低。
在 Java 中,Future
类只是一个泛型接口,位于 java.util.concurrent
包下,其中定义了 5 个方法,主要包括下面这 4 个功能:
(1)取消任务;(2)判断任务是否被取消;(3)判断任务是否已经执行完成;(4)获取任务执行结果。
// V 代表了Future执行的任务返回值的类型 public interface Future<V> { // 取消任务执行 // 成功取消返回 true,否则返回 false boolean cancel(boolean mayInterruptIfRunning); // 判断任务是否被取消 boolean isCancelled(); // 判断任务是否已经执行完成 boolean isDone(); // 获取任务执行结果 V get() throws InterruptedException, ExecutionException; // 指定时间内没有返回计算结果就抛出 TimeOutException 异常 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException }
总结:有一个任务,提交给了 Future
来处理。任务执行期间我自己可以去做任何想做的事情。并且,在这期间我还可以取消任务以及获取任务的执行状态。一段时间之后,我就可以 Future
那里直接取出任务执行结果。
2.Callable 和 Future 有什么关系?
FutureTask
是一个类,提供了 Future
接口的基本实现,常用来封装 Callable
和 Runnable
,具有取消任务、查看任务是否执行完成以及获取任务执行结果的方法。ExecutorService.submit()
方法返回的其实就是 Future
的实现类 FutureTask
。 FutureTask
不光实现了 Future
接口,还实现了Runnable
接口,因此可以作为任务直接被线程执行。 FutureTask
有两个构造函数,可传入 Callable
或者 Runnable
对象。实际上,传入 Runnable
对象也会在方法内部转换为Callable
对象。 FutureTask
相当于对Callable
进行了封装,管理着任务执行的情况,存储了 Callable
的 call
方法的任务执行结果。FutureTask 的线程安全由CAS来保证。public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; } public FutureTask(Runnable runnable, V result) { // 通过适配器RunnableAdapter来将Runnable对象runnable转换成Callable对象 this.callable = Executors.callable(runnable, result); this.state = NEW; }
3.FutureTask使用:
import java.util.concurrent.*; public class CallDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { /** * 第一种方式:Future + ExecutorService * Task task = new Task(); * ExecutorService service = Executors.newCachedThreadPool(); * Future<Integer> future = service.submit(task1); * service.shutdown(); */ /** * 第二种方式: FutureTask + ExecutorService * ExecutorService executor = Executors.newCachedThreadPool(); * Task task = new Task(); * FutureTask<Integer> futureTask = new FutureTask<Integer>(task); * executor.submit(futureTask); * executor.shutdown(); */ /** * 第三种方式:FutureTask + Thread */ // 2. 新建FutureTask,需要一个实现了Callable接口的类的实例作为构造函数参数 FutureTask<Integer> futureTask = new FutureTask<Integer>(new Task()); // 3. 新建Thread对象并启动 Thread thread = new Thread(futureTask); thread.setName("Task thread"); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread [" + Thread.currentThread().getName() + "] is running"); // 4. 调用isDone()判断任务是否结束 if(!futureTask.isDone()) { System.out.println("Task is not done"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } int result = 0; try { // 5. 调用get()方法获取任务结果,如果任务没有执行完成则阻塞等待 result = futureTask.get(); } catch (Exception e) { e.printStackTrace(); } System.out.println("result is " + result); } // 1. 继承Callable接口,实现call()方法,泛型参数为要返回的类型 static class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("Thread [" + Thread.currentThread().getName() + "] is running"); int result = 0; for(int i = 0; i < 100;++i) { result += i; } Thread.sleep(3000); return result; } } }
4.CompletableFuture 类有什么用?
Future
在实际使用过程中存在一些局限性比如不支持异步任务的编排组合、获取计算结果的 get()
方法为阻塞调用。
Java 8 才被引入CompletableFuture
类可以解决Future
的这些缺陷。CompletableFuture
除了提供了更为好用和强大的 Future
特性之外,还提供了函数式编程、异步任务编排组合(可以将多个异步任务串联起来,组成一个完整的链式调用)等能力。
CompletableFuture
同时实现了 Future
和 CompletionStage
接口。
CompletionStage
接口描述了一个异步计算的阶段。很多计算可以分成多个阶段或步骤,此时可以通过它将所有步骤组合起来,形成异步计算的流水线。
CompletionStage
接口中的方法比较多,CompletableFuture
的函数式能力就是这个接口赋予的。从这个接口的方法参数你就可以发现其大量使用了 Java8 引入的函数式编程。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY