荒腔走板
大家好,我是 why,欢迎来到我连续周更优质原创文章的第 60 篇。
老规矩,先来一个简短的荒腔走板,给冰冷的技术文注入一丝色彩。
上面这图是我五年前,在学校宿舍拍的。
前几天由于有点事情,打开了多年没有打开的 QQ。然后突然推送了一个“那年今日”发送的动态。
这张图片就是那个动态里面的。
2015 年 8 月的时候正是大三放暑假的时间,但是那个暑假我找了一个实习,所以暑假期间住在学校里面。宿舍就我一个人。那个时候我完全没有意识到,这是我程序猿生涯的一个真正的开端,也是我学生时代提前结束的宣告。
8 月 5 日凌晨,一只小猫突然蹿到了宿舍里面,在宿舍里面旁若无人的,像宿管阿姨一样审查着一切东西。甚至直接跳到桌子上,看着我敲代码。完全不怕我的样子。
于是我把它放到了我的自行车上,当模特拍了几张照片。
初见这只小猫时的那种惊喜我还记忆犹新,但是这波回忆杀给我的更大的冲击是:原来,这件事已经过去五年了。
如果没有QQ的这个提醒,你让我想这件事是发生在什么时候的,我的第一反应肯定是好多年前的事情了吧,慢慢咂摸之后有可能才想起,原来是大三暑假的时候的事情,然后再仔细一算,原来是仅仅五年前的事情呀。
短短的五年怎么发生了怎么多事情啊,把这五年塞的满满当当的。
不知道为什么如果把人生求学、步入社会的各个阶段分开来看,我每次回头望的时候都感觉这好像是别人的故事啊。
幸好我自己记录了下来,幸好这真的是我自己的故事。
好了,说回文章。
你就是写了个假异步
先去我的第一篇公众号文章中拿张图片:《Dubbo 2.7新特性之异步化改造》
这是 rpc 的四种调用方式:
文本主要分享这个 future 的调用方式,不讲 Dubbo 框架,这里只是一个引子。
谈到 future 的时候大家都会想到异步编程。但是你仔细看框起来这里:
本文将带你从阉割版的 future 聊到升级版的 Google Guava 的 future,最后谈谈加强版的 future 。
先聊聊线程池的提交方式
谈到 Future 的时候,我们基本上就会想到线程池,想到它的几种提交方式。
先是最简单的,execute 方式提交,不关心返回值的,直接往线程池里面扔任务就完事:
public class JDKThreadPoolExecutorTest { public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10)); //execute(Runnable command)方法。没有返回值 executor.execute(() -> { System.out.println("关注why技术"); }); Thread.currentThread().join(); } }
可以看一下 execute 方法,接受一个 Runnable 方法,返回类型是 void:
有三种 submit。这三种按照提交任务的类型来算分为两个类型。
- 提交执行 Runnable 类型的任务。
- 提交执行 Callable 类型的任务。
但是返回值都是 Future,这才是我们关心的东西。
也许你知道线程池有三种 submit 方法,但是也许你根本不知道里面的任务分为两种类型,你就只知道往线程池里面扔,也不管扔的是什么类型的任务。
我们先看一下 Callable 类型的任务是怎么执行的:
public class JDKThreadPoolExecutorTest { public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10)); Future<String> future = executor.submit(() -> { System.out.println("关注why技术"); return "这次一定!"; }); System.out.println("future的内容:" + future.get()); Thread.currentThread().join(); } }
这里利用 lambda 表达式,直接在任务体里面带上一个返回值,这时你看调用的方法就变成了这个:
标号为 ① 的方法扔进去一个 Runable 的任务,返回一个 Future,而这个返回的 Future ,相当于是返回了一个寂寞。下面我会说到原因。
标号为 ② 的方法扔进去一个 Runable 的任务的同时,再扔进去一个泛型 T ,而巧好返回的 Future 里面的泛型也是 T,那么我们大胆的猜测一下这就是同一个对象。如果是同一个对象,说明我们可以一个对象传到任务体里面去一顿操作,然后通过 Future 再次拿到这个对象的。一会就去验证。
来,先验证标号为 ① 的方法,我为啥说它返回了一个寂寞。
首先,还是先把测试案例放在这里:
public class JDKThreadPoolExecutorTest { public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10)); Future<?> future = executor.submit(() -> { System.out.println("关注why技术"); }); System.out.println("future的内容:" + future.get()); Thread.currentThread().join(); } }
可以看到,确实是调用的标号为 ① 的方法: