目录
如果在我们的业务中某些功能需要其他一些功能执行完成之后才能开始执行(比如获取其他功能的返回结果),这样就需要用到异步编排功能。
Future 是 Java 5 添加的类,用来描述一个异步计算的结果。你可以使用isDone
方法检查计算是否完成,或者使用get
阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel
方法停止任务的执行。
虽然Future
以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果。
Future的使用限制:
- 并发执行多任务:Future只提供了get()方法获取结果,并且是阻塞的。所以,除了等待,别无他法
- 无法对多个任务进行链式调度:如果我们希望在计算任务完成后执行特定的动作,比如发送邮件,但是Future中没有提供这样的能力
- 无法组合多个任务:如果我们运行了10个任务,并且期望在他们全部执行结束后执行特定动作,在Future中是无法实现的。
- 没有异常处理:Future接口中没有关于异常处理的方法
在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture
,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture
的方法。 CompletableFuture
类实现了 Future 接口,所以你还是可以像以前一样通过get
方法阻塞或者轮询的方式获得结果。
1、创建异步对象
CompletableFuture
提供了四个静态方法来创建一个异步操作。
runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的 (使用get方法得到返回值)
可以传入自定义的线程池,否则就用默认的线程池
@Test
public void test3() throws ExecutionException, InterruptedException {
System.out.println("主函数开始执行");
CompletableFuture<Void> runAsync=CompletableFuture.runAsync(() -> {
System.out.println("线程 "+Thread.currentThread().getName()+"=》开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程 "+Thread.currentThread().getName()+"=》执行结束");
});
CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println("线程 "+Thread.currentThread().getName()+"=》开始执行");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程 "+Thread.currentThread().getName()+"=》执行结束");
return Thread.currentThread().getName()+"线程返回的信息";
});
runAsync.get();
System.out.println(supplyAsync.get());
System.out.println("主函数执行结束");
}
2、计算完成时回调方法
whenCompleteXXX可以得到计算结果和异常,但是不能修改返回值。
exceptionally 可以得到异常结果,可以修改返回值。
带有
Async
默认是异步执行的.
示例代码:
@Test
void contextLoads() throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println("当前线程:" + Thread.currentThread().getName());
int i = 10/0;
return 1024;
}
}).whenComplete(new BiConsumer<Integer, Throwable>() {
@Override
public void accept(Integer res, Throwable exception) {
System.out.println("返回结果是:" + res);
System.out.println("异常是:" + exception);
}
}).exceptionally(new Function<Throwable, Integer>() {
@Override
public Integer apply(Throwable exception) {
System.out.println("异常是:" + exception);
return 666;
}
});
Integer integer = future.get();
System.out.println(integer);
}
返回结果:
当前线程:pool-1-thread-1
返回结果是:null
异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
666
3、handle方法
handle方法算是结合了上面的whenComplete
方法和exceptionally
方法。
示例代码
@Test
void contextLoads() throws ExecutionException, InterruptedException {
CompletableFuture<Object> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println("当前线程:" + Thread.currentThread().getName());
int i = 10/0;
return 1024;
}
}).handle((res,exception)->{
//如果发生异常,res就等于空
if(res!=null){
return "返回的结果为:"+res;
}
//如果没有发生异常,exception就为空
if(exception!=null){
return "发生了异常,异常为:"+exception.getCause();
}
return 0;
});
System.out.println(future. Get());
}
返回结果
4、线程串行化方法
thenApply
方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
thenAccept
方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun
方法:只要上面的任务执行完成,就开始执行thenRun
,不能获得上一个任务的返回值。Function<?super T,?extend U> :
T:上一个任务返回结果的类型 。
U:当前任务的返回值类型。
@Test
public void test3() throws ExecutionException, InterruptedException {
CompletableFuture<Object> future = CompletableFuture.supplyAsync(new Supplier<Object>() {
@Override
public Object get() {
return 123;
}
}).thenApply(new Function<Object, Object>() {
@Override
public Object apply(Object o) {
System.out.println("上一个任务的返回值:"+o);
return 456;
}
});
System.out.println(future. Get());
}
执行结果
5、两任务组合 - 都要完成
两个任务必须都完成,才能触发该任务。
thenCombine
:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
thenAcceptBoth
:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有返回值。
runAfterBoth
:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后, 处理该任务。
示例代码
@Test
void contextLoads() throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println("future01开始");
System.out.println("future01结束");
return 1024;
}
}, service);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
System.out.println("future02开始");
System.out.println("future02结束");
return "hello";
}
}, service);
CompletableFuture<String> future03 = future01.thenCombine(future02, (f1, f2) -> {
System.out.println("future01的返回结果:" + f1);
System.out.println("future02的返回结果:" + f2);
return "future03";
});
System.out.println("==============================");
System.out.println(future03.get());
}
返回结果:
future01开始
future01结束
future02开始
future02结束
future01的返回结果:1024
future02的返回结果:hello
==============================
future03
6、两任务组合 - 一个完成
当两个任务中,任意一个 future 任务完成的时候,执行任务。
applyToEither
:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
acceptEither
:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
runAfterEither
:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值
示例代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01开始");
System.out.println("future01结束");
return 1024;
}, service);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future02结束");
return "hello";
}, service);
CompletableFuture<String> future03 = future01.applyToEither(future02, res -> {
System.out.println("返回值:" + res);
return "future03";
});
System.out.println("==============================");
System.out.println(future03.get());
}
返回结果:
future01开始
future01结束
future02开始
返回值:1024
==============================
future03
future02结束
7、多任务组合
allOf
:等待所有任务完成
anyOf
:只要有一个任务完成
示例代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01开始");
System.out.println("future01结束");
return 1024;
}, service);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future02结束");
return "hello";
}, service);
CompletableFuture<Object> future03 = CompletableFuture.supplyAsync(() -> {
System.out.println("future03开始");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future03结束");
return "RedMi";
}, service);
CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
allOf.get();//等待三个任务都完成
System.out.println("==============================");
System.out.println("三个任务都执行完成了");
}
返回结果:
future01开始
future01结束
future02开始
future03开始
future03结束
future02结束
==============================
三个任务都执行完成了
标签:异步,System,编排,CompletableFuture,future02,println,future01,out From: https://blog.csdn.net/stduyc/article/details/137176973