这就相当于异步任务执行过程中抛出了异常,而你只有在调用了 get 方法(打电话操作)之后才知道原来异常了。
而真正的异步是你不用等我,我好了我就叫你。
就像女神接到男神的电话时说的:我需要一点时间准备一下,你先玩自己的吧,我一会好了给你打电话。
这让我想起了好莱坞原则:Don't Call Us,We'll Call you!
接下来,让我们见识一下真正的异步。
什么叫真正的:“你先玩自己的,我一会好了叫你。”
Guava 的 Future
女神说的:“好了叫你”。
就是一种回调机制。说到回调,那么我们就需要在异步任务提交之后,注册一个回调函数就行。
Google 提供的 Guava 包里面对 JDK 的 Future 进行了扩展:
新增了一个 addListenter 方法,入参是一个 Runnable 的任务类型和一个线程池。
使用方法,先看代码:
public class JDKThreadPoolExecutorTest { public static void main(String[] args) throws Exception { ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); ListenableFuture<String> listenableFuture = executor.submit(() -> { System.out.println(Thread.currentThread().getName()+"-女神:我开始化妆了,好了我叫你。"); TimeUnit.SECONDS.sleep(5); return "化妆完毕了。"; }); listenableFuture.addListener(() -> { try { System.out.println(Thread.currentThread().getName()+"-future的内容:" + listenableFuture.get()); } catch (Exception e) { e.printStackTrace(); } }, executor); System.out.println(Thread.currentThread().getName()+"-等女神化妆的时候可以干点自己的事情。"); Thread.currentThread().join(); } }
首先创建线程池的方式变了,需要用 Guava 里面的 MoreExecutors 方法装饰一下:
ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
然后用装饰后的 executor 调用 submit 方法(任意一种),就会返回 ListenableFuture
,拿到这个 ListenableFuture 之后,我们就可以在上面注册监听:
从运行结果可以看出来:获取运行结果是在另外的线程里面执行的,完全没有阻塞主线程。
和之前的“假异步”还是有很大区别的。
除了上面的 addListener 方法外,其实我更喜欢用 FutureCallback 的方式。