按理来说也就是可以用了。
但是如果你不需要返回值,它还提供了这样的写法:
正常情况和异常情况分开处理。
优雅,非常优雅。
还有更牛的。
前面我们化妆的线程和化妆完成的线程不是同一个线程吗:
只需要把调用的方法从 whenComplete 改为 whenCompleteAysn 即可。
同样,这个方法也支持指定线程池:
你可以去看 CompletableFuture 里面有非常多的 Aysn 结尾的方法,大多都是干这个事儿的,以异步的形式在线程池中执行。
如果说上面的介绍让你觉得不过如此,那么再介绍一个 Future 没有的东西。
假设现在需求是这样的。
女神化完妆之后,还要花个一小会选衣服,不过分吧。
也就是说我们现在有两个异步任务,第一个是化妆,第二个是选衣服。
选衣服要在化妆完成之后进行,这两个任务是串行的,用 CompletableFuture 怎么实现呢?
我把代码贴一下,为了看起来更加直观,我没有用链式调用:
public class MainTest { public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newFixedThreadPool(10); //任务一 CompletableFuture<String> makeUpFuture = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "-女神:我开始化妆了。"); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } return "化妆完毕了。"; }, executorService); //任务二(makeUpFuture是方法调用方,意思是等makeUpFuture执行完成后执行再执行) CompletableFuture<String> dressFuture = makeUpFuture.thenApply(makeUp -> { System.out.println(Thread.currentThread().getName() + "-女神:" + makeUp + "我开始选衣服啦,好了我叫你。"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return makeUp + "衣服也选好啦。靓仔,走去玩儿吧。"; }); //获取结果 dressFuture.thenAccept(result -> { System.out.println(Thread.currentThread().getName() + "-" + result); }); } }
这样输出结果就是这样的:
符合我们的预期。
假设我们想要选衣服的时候换另外一个线程怎么办呢?
别说不知道,这不刚才教你了吗,Async 结尾的方法,得活学活用起来:
前面讲的是多个异步任务串行执行,接下来再说一下并行。
CompletableFuture 里面提供了两个并行的方法:
两个方法的入参都是可变参数,就是一个个异步任务。
allOf 顾名思义就是入参的多个 CompletableFuture 都必须成功,才能继续执行。
而 anyOf 就是入参的多个 CompletableFuture 只要有一个成功就行。
还是举个例子。
假设,我是说假设啊,我是一个海王。
算了,我假设我有一个朋友吧。
他同时追求好几个女朋友。今天他打算约小美和小乖中的一个出门玩,随便哪个都行。谁先化妆完成,就约谁。另外一个就放她鸽子。
这个场景,我们就可以用 anyOf 来模拟,于是就出现了这样的代码:
从输出结果来看,最后和朋友约会的是小美。
都把小美约出来了,必须要一起吃个饭才行,对吧。
那么这个时候朋友问:小美,你想吃点什么呢?
小美肯定会回答:随便,就行,无所谓。
听到这样的回答,朋友心里就有底了,马上给出了一个方案:我们去吃沙县小吃或者黄焖鸡吧,哪一家店等的时间短,我们就去吃哪一家。
于是上面的代码,就变成了这样:
我把代码都放这里,你粘过去就能跑起来:
public class MainTest { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); CompletableFuture<String> xiaoMei = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "-小美:我开始化妆了,好了我叫你。"); try { int time = ThreadLocalRandom.current().nextInt(5); TimeUnit.SECONDS.sleep(time); System.out.println(Thread.currentThread().getName() + "-小美,化妆耗时:" + time); } catch (InterruptedException e) { e.printStackTrace(); } return "小美:化妆完毕了。"; }, executorService); CompletableFuture<String> xiaoGuai = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "-小乖:我开始化妆了,好了我叫你。"); try { int time = ThreadLocalRandom.current().nextInt(5); TimeUnit.SECONDS.sleep(time); System.out.println(Thread.currentThread().getName() + "-小乖,化妆耗时:" + time); } catch (InterruptedException e) { e.printStackTrace(); } return "小乖:化妆完毕了。"; }, executorService); CompletableFuture<Object> girl = CompletableFuture.anyOf(xiaoMei, xiaoGuai); girl.thenAccept(result -> { System.out.println("我看最后是谁先画完呢 = " + result); }); CompletableFuture<String> eatChooseOne = girl.thenApplyAsync((result) -> { try { TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(10)); } catch (InterruptedException e) { e.printStackTrace(); } return result + "这里人少,我们去吃沙县小吃吧!"; }, executorService); CompletableFuture<String> eatChooseTwo = girl.thenApplyAsync((result) -> { try { TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(10)); } catch (InterruptedException e) { e.printStackTrace(); } return result + "这里人少,我们去吃黄焖鸡吧!"; }, executorService); CompletableFuture.allOf(eatChooseOne, eatChooseTwo).thenAccept(result -> { System.out.println("最终结果:" + result); }); } }
如果你说,小孩子才做选择,大人是全部都要。
那么,你可以试着用一下 allOf,只是需要注意的是,allOf 是不带返回值的。
好了,写到这里我都感觉有点像是 API 教学了,没啥劲。所以 CompletableFuture 还有很多很多的方法,我就不一一介绍了。