最近在学习如何使用CompletableFuture这个新的并发类,通过搜索在DZone上发现了一篇文件,介绍使用CompletableFuture的20个例子,链接如下:https://dzone.com/articles/20-examples-of-using-javas-completablefuture。
每次JDK推出一个新的类/数据结构之后,我想很多人的第一个问题是,这个类/数据结构在哪种场景下使用最合适,它能用来解决什么问题?只有弄清楚了适用的场景才能更深入地理解在什么地方可以用,以及怎么去用。
读完那20个例子,我发现有如下几点收获,分享给大家:
1、可以方便地用来运行异步程序
之前想要用Java来异步运行程序主要有两种方式:1)单独创建一个线程,执行start方法,或者2)创建一个executor线程池,然后提交任务到其中,相对来讲都比较麻烦,在一段业务逻辑代码里,需要插入创建线程或者线程池的语句,感觉不能“很自然”地引入异步处理。现在则可以使用CompletableFuture来方便地运行异步任务,例如:
CompletableFuture cf = CompletableFuture.runAsync(()->
assertTrue(Thread.currentThread().isDaemon());
randomSleep();
});
assertFalse(cf.isDone());
sleepEnough();
assertTrue(cf.isDone());
以Async结尾的方法会异步执行,其本质还是交给ForkJoinPool来异步执行。
2、串行执行一系列操作
在前一个阶段stage执行的方法结束之后,可以调用thenApply继续做操作,then意味着后面的动作在前面的动作结束之后运行,如果需要异步执行,选择带有async的方法thenApplyAsync。
CompletableFuture类实现了两个接口,Future 和 CompletionStage,CompletionStage是整个操作流程中的一个阶段stage,每个阶段stage完成后返回另一个stage,这样操作就可以串起来了。如果方法名字带有accept,则参数需要是实现Consumer接口的,可以是Consumer, BiConsumer;如果名字带有apply,则参数需要是实现Function接口的,可以是Function,BiFunction。
StringBuilderresult=newStringBuilder();
CompletableFuture.completedFuture("thenAccept message").thenAccept(s->result.append(s));
3、CompletableFuture执行异常结束
为了处理执行过程中的异常,可以给stage安排一个exception handler,也可以用异常来结束一个正在执行的stage,如下:
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase,
CompletableFuture.delayedExecutor(1,TimeUnit.SECONDS));
CompletableFuture exceptionHandler = cf.handle((s,th)->{return(th!=null)?"message upon cancel":""; });
cf.completeExceptionally(newRuntimeException("completed exceptionally"));
assertTrue("Was not completed exceptionally",cf.isCompletedExceptionally());
try{
cf.join();
fail("Should have thrown an exception");
}catch(CompletionException ex) {// just for testing
assertEquals("completed exceptionally",ex.getCause().getMessage());
}
assertEquals("message upon cancel",exceptionHandler.join());
completeExceptionally方法可以用一个异常结束cf,此时等在(join)方法上的代码会收到这个异常退出,如果给cf安排了一个exception handler,这个handler会得到执行,返回另一个字符串"message upon cancel"。
4、取消计算
通过cancel方法可以取消一个stage的运行,取消不是通过中断interrupt实现的,而是通过CancellationException,cancel()的效果跟completeExceptionally(new CancellationException())是等价的。