Future接口定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
Callable接口中定义了需要有返回的任务需要实现的方法。
应用: 比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,过了一会才去获取子任务的执行结果。
本源的Future接口相关架构
FutureTask 的使用
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
return 1024;
});
new Thread(futureTask, "t1").start();
//1.不见不散(阻塞),只要出现get方法,不管是否计算完成都阻塞等待结果出来再运行
// System.out.println(futureTask.get());
//2.过时不候
// System.out.println(futureTask.get(2L,TimeUnit.SECONDS));
//3.不要阻塞,尽量用轮询替代
while (true) {
if (futureTask.isDone()) { // 判断是否完成
System.out.println("----result: " + futureTask.get());
break; //完成就break
} else {
System.out.println("还在计算中,别催,越催越慢,再催熄火");
}
}
FutureTask的缺点:
1. get()阻塞 : 一旦调用get()方法,不管是否计算完成都会导致阻塞。如果使用 futureTask.get() 最好放在最后
2. isDone()轮询 : 轮询的方式会耗费无谓的CPU资源,而且也不见得能及时地得到计算结果. 如果想要异步获取结果,通常都会以轮询的方式去获取结果,但尽量不要阻塞
总结:不见不散futureTask.get() —> 过时不候futureTask.get(2L,TimeUnit.SECONDS) —> 轮询futureTask.isDone()
想完成一些复杂的任务
- 应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知
- 将两个异步计算合成一个异步计算,这两个异步计算互相独立,同时第二个又依赖第一个的结果。
- 当Future集合中某个任务最快结束时,返回结果。
- 等待Future结合中的所有任务都完成。
- 。。。。。。
接口CompletionStage
代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段
,有些类似Linux系统的管道分隔符传参数。
类CompletableFuture 可以完全替代FutureTask
CompletableFuture supplyAsync(Supplier supplier)
代码演示:
结果:
面试题:线程池用在什么地方?
上述方法的Executor executor参数说明
- 没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool() 作为它的线程池执行异步代码。
- 如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码
CompletableFuture四个函数
CompletableFuture的优点
函数式编程已经主流
Lambda +Stream+链式调用+Java8函数式编程带走
join() = get() 都是获取结果 ,都会造成阻塞
get() 会抛出异常,join() 不抛出异常
功能→性能 (案例:比价需求)
获取结果
public T join()
public T get() 不见不散
public T get(long timeout, TimeUnit unit) 过时不候
public T getNow(T valueIfAbsent) 没有计算完成的情况下,给我一个替代结果
立即获取结果不阻塞 计算完,返回计算完成后的结果, 没算完,返回设定的valueIfAbsent值
主动触发计算
public boolean complete(T value) 是否打断get方法立即返回括号值
1. thenApply 计算结果存在依赖关系,这两个线程串行化
由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停。
2. handle 有异常也可以往下一步走,根据带的异常参数可以进一步处理
结果
总结
一般用不带尾巴的
接收任务的处理结果,并消费处理,无返回结果
thenAccept
两个CompletionStage任务都完成后,最终能把两个任务的结果一起交给thenCombine 来处理
先完成的先等着,等待其它分支任务