概述
Java8之前用 Future 处理异步请求, 当你需要获取任务结果时, 通常的做法是调用 get(long timeout, TimeUnit unit) 此方法会阻塞当前的线程, 如果任务处理超时, 就会抛出一个 TimeoutException
@Testpublic void test1() throwsInterruptedException, ExecutionException, TimeoutException {
ExecutorService executorService=Executors.newCachedThreadPool();
Future f = executorService.submit(() -> "ceshishanghu");
String s= f.get(3, TimeUnit.SECONDS);
System.out.println(s);
}
在Java8中引入了 CompletableFuture, 使用它提供的API可以不用像之前那样阻塞式或轮询的获取某个异步任务的结果, CompletableFuture 会在异步任务处理完成后自动进行回调, 让你可以链式的组合多个异步任务。
CompletableFuture 类中提供了许多以 Async 后缀结尾的方法。通常而言,名称中不带 Async 的方法和它的前一个任务一样,在同一个线程中运行。而名称以 Async 结尾的方法会将后续的任务提交到一个线程池,所以每个任务是由不同的线程处理的。
静态工厂方法
supplyAsync(): 异步处理任务, 有返回值
runAsync(): 异步处理任务, 没有返回值
allOf(): 需要等待所有的异步任务都执行完毕,才会返回一个新的CompletableFuture
anyOf(): 任意一个异步任务执行完毕,就会返回一个新的CompletableFuture
completedFuture(): 这种方式获取的 CompletableFuture 不是异步的,它会等待获取明确的返回结果之后再返回一个已经完成的 CompletableFuture
@Testpublic voidtest2() {//创建一个已经有任务结果的CompletableFuture
CompletableFuture f1 = CompletableFuture.completedFuture("return value");//异步处理任务,有返回值
CompletableFuture f2 = CompletableFuture.supplyAsync(this::get);//异步处理任务,没有返回值
CompletableFuture f3 =CompletableFuture.runAsync(System.out::println);//需要等待所有的异步任务都执行完毕,才会返回一个新的CompletableFuture//CompletableFuture all = CompletableFuture.allOf(f1, f2, f3);//任意一个异步任务执行完毕,就会返回一个新的CompletableFuture
CompletableFuture any =CompletableFuture.anyOf(f1, f2, f3);
Object result=any.join();
System.out.println("result = " + result);//result = return value
}publicString get() {
delay();return "异步任务结果";
}public voiddelay() {try{
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
上面的示例中, allOf() 因为要等待所有的异步任务执行完成,所以要延时1秒钟才会返回一个新的 CompletableFuture, 而 anyOf() 则不需要等待所有的异步任务, 因为第一个异步最先完成, 所以控制台输出 result = return value 。
链式调用
A任务执行完毕, 继续执行B任务, B任务执行完毕, 继续执行C任务...
@Testpublic voidtest2() {
CompletableFuture f = CompletableFuture.supplyAsync(() ->{//测试抛异常后,handle()方法接受并处理//int x = 1 / 0;
return "这是一个栗子";
}).handle((res, ex)->{
System.out.println("handle res = " +res);if(Objects.nonNull(ex)) {
System.out.println("handle ex" +ex.getCause().getMessage());
}return Objects.nonNull(ex) ? 0 : 1;
}).thenApply(res->{
System.out.println("thenApply res = " +res);return res == 1 ? "success" : "error";
}).thenAccept(res-> System.out.println("thenAccept res = " +res)
).thenRun(()-> System.out.println("没有参数, 异步执行一个没有返回值的任务"));
f.join();
}
输出结果:
handle res =这是一个栗子
thenApply res= 1thenAccept res=success
没有参数, 异步执行一个没有返回值的任务
将上面 int x = 1 / 0; 这行代码取消注释, 重新运行结果如下:
handle res = nullhandle ex/by zero
thenApply res= 0thenAcc