https://blog.csdn.net/moakun/article/details/80153901
https://www.jianshu.com/p/6f3ee90ab7d3
/**
* @program: lightning-project
* @description:
* @author: lh
* @create: 2019-05-10 14:12
*/
public class CompletableFutureTest {
//callable提交后要获取结果还需要future去查询,那么就还需要轮询或者阻塞的去拿 future.get();
//反正需要显示地完成
//java8加入了CompletableFuture 实现了Future<T> 异步, CompletionStage<T> 代表一个特定的计算的阶段 也就是一步
//当一个Future可能需要显示地完成时,使用CompletionStage接口去支持完成时触发的函数和操作。
//包含几个基本方法 创建CompletableFuture thenApply(thenApply相当于回调函数(callback)) thenCombine整合两个计算结果
//whenComplete
//所谓异步调用其实就是实现一个可无需等待被调用函数的返回值而让操作继续运行的方法。在 Java 语言中,简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结果。但调用者仍需要取线程的计算结果。
public static void main(String[] agrs) {
//CompletableFuture的方法如果以Async结尾,它会异步的执行(没有指定executor的情况下), 异步执行通过ForkJoinPool实现,
// 它使用守护线程去执行任务。注意这是CompletableFuture的特性, 其它CompletionStage可以override这个默认的行为
CompletableFuture cf1 = CompletableFuture.runAsync(() -> {
if (Thread.currentThread().isDaemon()) {
System.out.println("cf1 is a daemon thread");
}
});
//在前一个阶段上应用函数
//Apply意味着返回的阶段将会对结果前一阶段的结果应用一个函数。
//getNow(null)方法在future完成的情况下会返回结果,就比如上面这个例子,否则返回null (传入的参数)。
//getNow可以作为降级值
CompletableFuture cf2 = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
return s.toUpperCase();
});
System.out.println("cf2 result" + cf2.getNow(null));
//使用定制的Executor在前一个阶段上异步应用函数
//异步方法一个非常有用的特性就是能够提供一个Executor来异步地执行CompletableFuture。
// 这个例子演示了如何使用一个固定大小的线程池来应用大写函数。
//这个流式的计算每一步都可以当做回调
ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() {
int count = 1;
@Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "custom-executor-" + count++);
}
});
CompletableFuture cf3 = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
if (Thread.currentThread().getName().startsWith("custom-executor-")) {
System.out.println("cf3 " + "startsWith custom-executor-");
}
return s.toUpperCase();
}, executor).thenApplyAsync(s -> {
s = s + "1";
System.out.println("cf3thenAcceptAsync异步执行完成 并触发回调s:" + s);
return s;
}
).whenCompleteAsync((x, ex) -> {
System.out.println("cf3"+x);
});
//如果不传一个线程池 就用内置的线程池
//whenCompleteAsync 就是完成了该干的事情 因为也没有返回值 但是不能再thenAccept后面不然无效
CompletableFuture cf4 = CompletableFuture.completedFuture(1)
.thenApplyAsync(s -> s + 10, executor).thenApplyAsync(s -> s * 10)
.whenCompleteAsync((x, ex) -> {
System.out.println("cf4"+x);
});
//thenAccept 被用于增加回调函数,相当于处理结果的作用 也就是消耗结果 但是没有返回值 所以相当于结束了 然后也再也不能get到值了
// thenAccept接收上一阶段的输出作为本阶段的输入
//thenRun 接受一个Runnable参数 表示下个操作开始了
CompletableFuture cf5 = CompletableFuture.completedFuture(1)
.thenApplyAsync(s -> s + 10, executor).thenApplyAsync(s -> s * 10)
.thenAccept(x -> {
System.out.println("cf5"+x);
}).thenRun(()->{
});
if(1==2){
//如果不是1==2这里会死循环
while (cf5.getNow(null) == null){
cf5.getNow(null);
}
}
//异常处理
//前面说的除了whenCompleteAsync 都没有异常处理的能力
//有三个可以处理异常
// whenCompleteAsync 可以处理异常但是没有返回值
// handle 可以处理异常 但是有返回值
// exceptionally(补偿 相当于catch)
//whenCompleteAsync 接受一个参数和异常 handle
//还有很多可以对结果就行合并的操作
//也可以选一个快的执行applyToEither
//谁快用谁acceptEither
//两个CompletionStage 任何一个完成了都可以进行下一步
//看源码 其实每一步都生成了一个CompletableFuture 估计是用空间换时间
//如何保证顺序
//虽然是异步的而且懒加载的 但是对于内部的数据其实是顺序执行的 意思就是加入线程池 消费
//消费完了 再下一个 代码的执行是自旋然后判断队列里面有没有 只有没有了 才会放进去
//所以这里说的异步不是每一步 拆出来并行执行的
//
}
}