从JDK8开始,在Concurrent包中提供了一个强大的异步编程工具CompletableFuture。在JDK8之前,异步编程可以通过线程池和Future来实现,但功能还不够强大。CompletableFuture的出现,使Java的异步编程能力向前迈进了一大步。
CompletableFuture,它是对并发编程的增强,它可以方便地将多个有一定依赖关系的异步任务以流水线的方式组合在一起,大大简化多异步任务的开发。
CompletableFuture,它是一个具体的类,实现了两个接口,一个是Future,另一个是CompletionStage。Future表示异步任务的结果,而CompletionStage的字面意思是完成阶段。多个CompletionStage可以以流水线的方式组合起来,对于其中一个CompletionStage,它有一个计算任务,但可能需要等待其他一个或多个阶段完成才能开始,它完成后,可能会触发其他阶段开始运行。CompletionStage提供了大量方法,使用它们,可以方便地响应任务事件,构建任务流水线,实现组合式异步编程。
最简单的用法
CompletableFuture实现了Future接口,所以它也具有Future的特 性:调用get()方法会阻塞在那,直到结果返回。
CompletableFuture<String> completableFuture = new CompletableFuture<String>(); String result = completableFuture.get();//调用者阻塞,等待结果返回
另外1个线程调用complete方法完成该Future,则所有阻塞在get ()方法的线程都将获得返回结果。
completableFuture.complete("this is a test result");
提交任务:runAsync与supplyAsync
上面的例子是一个空的任务,下面尝试提交一个真的任务,然后 等待结果返回。
例1:runAsync(Runnable)
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { System.out.println("testtask is running"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }); future1.get();//主线程阻塞,等待任务执行完成
CompletableFuture.runAsync ( .. ) 传 入 的 是 一 个 Runnable 接 口,在上面的代码中是使用了Java 8的lambda表达式的写法,和定义 一个Runnable对象是等价的。
例2:supplyAsync(Supplier)
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() { public String get() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "test result"; } }); String result = future2.get();//主线程阻塞,等待结果返回 System.out.println(result);//test result
例2和例1的区别在于,例2的任务有返回值。
通过上面两个例子可以看出,在基本的用法上,CompletableFuture和Future很相似,都可以提交两类任务:一类是无返回值的,另一 类是有返回值的。
链式的CompletableFuture:thenRun、thenAccept和 thenApply
对于 Future,在提交任务之后,只能调用 get()等结果返回; 但对于 CompletableFuture,可以在结果上面再加一个callback,当 得到结果之后,再接着执行callback。
例1:thenRun(Runnable)