那只需要在线程 1 的FutureTask 中获取 线程 2 FutureTask 的返回结果就可以了,我们稍稍修改一下程序:
@Slf4j public class MakeTeaExample1 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(2); // 创建线程2的FutureTask FutureTask<String> ft2 = new FutureTask<String>(new T2Task()); // 创建线程1的FutureTask FutureTask<String> ft1 = new FutureTask<String>(new T1Task(ft2)); executorService.submit(ft1); executorService.submit(ft2); executorService.shutdown(); } static class T1Task implements Callable<String> { private FutureTask<String> ft2; public T1Task(FutureTask<String> ft2) { this.ft2 = ft2; } @Override public String call() throws Exception { log.info("T1:洗水壶..."); TimeUnit.SECONDS.sleep(1); log.info("T1:烧开水..."); TimeUnit.SECONDS.sleep(15); String t2Result = ft2.get(); log.info("T1 拿到T2的 {}, 开始泡茶", t2Result); return "T1: 上茶!!!"; } } static class T2Task implements Callable<String> { @Override public String call() throws Exception { log.info("T2:洗茶壶..."); TimeUnit.SECONDS.sleep(1); log.info("T2:洗茶杯..."); TimeUnit.SECONDS.sleep(2); log.info("T2:拿茶叶..."); TimeUnit.SECONDS.sleep(1); return "福鼎白茶"; } } }来看程序运行结果:
知道这个变化后我们再回头看 ExecutorService 的三个 submit 方法:
<T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> Future<T> submit(Callable<T> task);第一种方法,逐层代码查看到这里:
你会发现,和我们改造烧水泡茶的程序思维是相似的,可以传进去一个 result,result 相当于主线程和子线程之间的桥梁,通过它主子线程可以共享数据
第二个方法参数是 Runnable 类型参数,即便调用 get() 方法也是返回 null,所以仅是可以用来断言任务已经结束了,类似 Thread.join()
第三个方法参数是 Callable 类型参数,通过get() 方法可以明确获取 call() 方法的返回值
到这里,关于 Future 的整块讲解就结束了,还是需要简单消化一下的
总结如果熟悉 Javascript 的朋友,Future 的特性和 Javascript 的 Promise 是类似的,私下开玩笑通常将其比喻成男朋友的承诺
回归到Java,我们从 JDK 的演变历史,谈及 Callable 的诞生,它弥补了 Runnable 没有返回值的空缺,通过简单的 demo 了解 Callable 与 Future 的使用。 FutureTask 又是 Future接口的核心实现类,通过阅读源码了解了整个实现逻辑,最后结合FutureTask 和线程池演示烧水泡茶程序,相信到这里,你已经可以轻松获取线程结果了
烧水泡茶是非常简单的,如果更复杂业务逻辑,以这种方式使用 Future 必定会带来很大的会乱(程序结束没办法主动通知,Future 的链接和整合都需要手动操作)为了解决这个短板,没错,又是那个男人 Doug Lea, CompletableFuture 工具类在 Java1.8 的版本出现了,搭配 Lambda 的使用,让我们编写异步程序也像写串行代码那样简单,纵享丝滑
接下来我们就了解一下 CompletableFuture 的使用
灵魂追问你在日常开发工作中是怎样将整块任务做到分工与协作的呢?有什么基本准则吗?
如何批量的执行异步任务呢?
参考Java 并发编程实战
Java 并发编程的艺术
Java 并发编程之美
个人博客:https://dayarch.top
加我微信好友, 进群娱乐学习交流,备注「进群」
前沿 Java 技术干货分享
高效工具汇总 | 回复「工具」
面试问题分析与解答
技术资料领取 | 回复「资料」