CompletableFuture.supplyAsync
表示创建带返回值的异步任务的,相当于ExecutorService submit(Callable task) 方法CompletableFuture.runAsync
表示创建无返回值的异步任务CompletableFuture.thenApply
和CompletableFuture.thenApplyAsync
表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中
(注:job1执行结束后,将job1的方法返回值作为入参传递到job2中并立即执行job2。thenApplyAsync与thenApply的区别在于,前者是将job2提交到线程池中异步执行,实际执行job2的线程可能是另外一个线程,后者是由执行job1的线程立即执行job2,即两个job都是同一个线程执行的)
CompletableFuture.thenAccept
thenAccept 同 thenApply 接收上一个任务的返回值作为参数,但是无返回值CompletableFuture.thenRun
thenRun 的方法没有入参,也没有返回值CompletableFuture.exceptionally
exceptionally方法指定某个任务执行异常时执行的回调方法,会将抛出异常作为参数传递到回调方法中。CompletableFuture.whenComplete
是当某个任务执行完成后执行的回调方法,会将执行结果或者执行期间抛出的异常传递给回调方法,如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常
测试案例
@Test
public void test10() throws Exception {
// 创建异步执行任务:
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
if(true){
throw new RuntimeException("test");
}else{
return 1.2;
}
});
//cf执行完成后会将执行结果和执行过程中抛出的异常传入回调方法,如果是正常执行的则传入的异常为null
//所以下面两个参数a,b 分别对应cf的返回值,cf抛出的异常。一般而言,如果cf运行正常没有出异常的情况下,a就有值,而b就是null。而如果cf里面抛异常了,那a就是null,b就是异常参数传进来
CompletableFuture<Double> cf2=cf.whenComplete((a,b)->{
if(b!=null){
log.error("cf执行异常,异常信息={}",b.getMessage());
}else{
log.info("cf执行正常,没有抛任何异常。且cf执行的结果={}",a);
}
});
//如果cf是正常执行的,cf2.get的结果就是cf执行的结果
//如果cf是执行异常,则cf2.get会抛出异常
System.out.println("cf2的结果="+cf2.get());
}
CompletableFuture.handle
跟whenComplete函数基本一致,区别在于handle的回调方法有返回值,必须要return一个值,且handle方法得到的CompletableFuture的执行结果与前一个CompletableFuture的执行结果无关
测试案例
@Test
public void test10() throws Exception {
// 创建异步执行任务:
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
if(true){
throw new RuntimeException("test");
}else{
return 1.2;
}
});
//cf执行完成后会将执行结果和执行过程中抛出的异常传入回调方法,如果是正常执行的则传入的异常为null
CompletableFuture<String> cf2=cf.handle((a,b)->{
if(b!=null){
log.error("cf执行异常,异常信息={}",b.getMessage());
}else{
log.info("cf执行正常,没有抛任何异常。且cf执行的结果={}",a);
}
//之所以加下面的代码,是因为handle函数里面需要有return返回值才行
if(b!=null){
return "run error";
}else{
return "run succ";
}
});
//get的结果是cf2的返回值,跟cf没关系了
System.out.println("cf2的返回值="+cf2.get());
//打印结果: cf2的返回值=run error
}
CompletableFuture.thenCombine
和CompletableFuture.thenAcceptBoth
和CompletableFuture.runAfterBoth
。
这三个方法都是将两个CompletableFuture组合起来,只有当那两个CompletableFuture都正常执行完了才会执行某个任务,区别在于,thenCombine会将两个任务的执行结果作为方法入参传递到指定方法中,且该方法有返回值;thenAcceptBoth同样将两个任务的执行结果作为方法入参,但是无返回值;runAfterBoth没有入参,也没有返回值。注意两个任务中只要有一个执行异常,则将该异常信息作为入参传递到这3个方法中。
@Test
public void test7() throws Exception {
// 创建异步执行任务:
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return 1.2;
});
CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
return 3.2;
});
//cf和cf2的异步任务都执行完成后,会将其执行结果作为方法入参传递给cf3,且有返回值
CompletableFuture<Double> cf3=cf.thenCombine(cf2,(a,b)->{
log.info("thenCombine,a={},b={}",a,b);
//打印结果a=1.2,b=3.2
return a+b;
});
//cf和cf2的异步任务都执行完成后,会将其执行结果作为方法入参传递给cf3,无返回值
CompletableFuture cf4=cf.thenAcceptBoth(cf2,(a,b)->{
log.info("thenAcceptBoth,a={},b={}",a,b);
//打印结果a=1.2,b=3.2
});
//cf4和cf3都执行完成后,执行cf5,无入参,无返回值
CompletableFuture cf5=cf4.runAfterBoth(cf3,()->{
log.info("runAfterBoth,无入参,无返回值");
});
//等待子任务执行完成
System.out.println("cf的返回结果="+cf.get());
System.out.println("cf2的返回结果="+cf2.get());
System.out.println("cf3的返回结果="+cf3.get());
System.out.println("cf4的返回结果="+cf4.get());
System.out.println("cf5的返回结果="+cf5.get());
//打印结果:
//cf的返回结果=1.2
//cf2的返回结果=3.2
//cf3的返回结果=4.4
//cf4的返回结果=null
//cf5的返回结果=null
}
CompletableFuture.applyToEither
和CompletableFuture. acceptEither
还有CompletableFuture. runAfterEither
。 这三个方法都是将两个CompletableFuture组合起来,只要其中一个CompletableFuture执行完了就会执行某个任务,其区别在于applyToEither会将已经执行完成的任务的执行结果作为方法入参,并有返回值;acceptEither同样将已经执行完成的任务的执行结果作为方法入参,但是没有返回值;runAfterEither没有方法入参,也没有返回值。注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。
@Test
public void test8() throws Exception {
// 创建异步执行任务:
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
int i = random.nextInt()%10;
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("cf执行完毕");
return 1.2;
});
CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{
int i = random.nextInt()%10;
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("cf2执行完毕");
return 3.2;
});
//cf和cf2中任何一个先执行完,会将其执行结果作为方法入参传递给cf3,且有返回值
CompletableFuture<Double> cf3=cf.applyToEither(cf2,(result)->{
log.info("cf3开始执行了,接收到的result={},当前时间={}",result,LocalDateTime.now());
int i = random.nextInt()%10;
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("cf3开始执行完毕");
return result;
});
//cf和cf2的任何一个先执行完会将其执行结果作为方法入参传递给cf4,无返回值
CompletableFuture cf4=cf.acceptEither(cf2,(result)->{
log.info("cf4开始执行了,接收到的result={},当前时间={}",result,LocalDateTime.now());
int i = random.nextInt()%10;
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("cf4开始执行完毕");
});
//cf4和cf3中任何一个执行完就立刻执行cf5,无入参,无返回值
CompletableFuture cf5=cf4.runAfterEither(cf3,()->{
log.info("cf5开始执行了");
});
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
测试结果:
CompletableFuture.thenCompose
这个函数跟CompletableFuture.thenApply
很相似。但是有点区别,thenApply()转换的是泛型中的类型,相当于将CompletableFuture<T>
转换生成新的CompletableFuture<U>
而thenCompose()用来连接两个CompletableFuture,是生成一个新的CompletableFuture。
@Test
public void test9() throws Exception {
// 创建异步执行任务:
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return 1.2;
});
CompletableFuture<String> cf2= cf.thenCompose((param)->{
log.info("param={}",param);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return "job3 test";
});
});
log.info("cf2的结果={}",cf2.get());
}
运行结果
CompletableFuture.allOf
返回的CompletableFuture是多个任务都执行完成后才会执行,只要有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null。
// 创建异步执行任务:
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
throw new RuntimeException("test");
//return 1.2;
});
CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
return 2.2;
});
CompletableFuture<Double> cf3 = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(1300);
} catch (InterruptedException e) {
}
return 3.2;
});
//allof等待所有任务执行完成才执行cf4,如果有一个任务异常终止,则cf4.get时会抛出异常,都是正常执行,cf4.get返回null
//如果cf,cf2,cf3中至少有一个任务出现了异常,那么下面的a就是null,b就是异常信息,如果所有任务都正常,那a也是null,b是null
CompletableFuture cf4=CompletableFuture.allOf(cf,cf2,cf3).whenComplete((a,b)->{
if(b!=null){
log.error("cf,cf2,cf3中至少有一个任务出现了异常,异常信息={}",b.getMessage());
}else{
log.error("cf,cf2,cf3任务全部执行成功,a={}",a);
}
});
log.info("cf4执行完毕,结果={}",cf4.get());
}
运行结果
CompletableFuture.anyOf
anyOf 的含义是只要有任意一个 CompletableFuture 结束,就可以做 接下来的事情,而无须像 AllOf 那样,等待所有的 CompletableFuture 结束。但由于每个 CompletableFuture 的返回值类型都可能不同,任意一个, 意味着无法判断是什么类型,所以 anyOf 的返回值是CompletableFuture<Object>
类型
@Test
public void test11() throws Exception {
// 创建异步执行任务:
CompletableFuture<String> cf = CompletableFuture.supplyAsync(()->{
log.info("cf执行开始了");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
log.info("cf执行开始结束");
return "xiaoming";
});
CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{
log.info("cf2执行开始了");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
log.info("cf2执行开始结束");
return 2.2;
});
CompletableFuture<Double> cf3 = CompletableFuture.supplyAsync(()->{
log.info("cf3执行开始了");
try {
Thread.sleep(1300);
} catch (InterruptedException e) {
}
log.info("cf3执行开始结束");
return 3.2;
});
//anyOf是只有一个任务执行完成,无论是正常执行或者执行异常,都会执行cf4,cf4.get的结果就是已执行完成的任务的执行结果
CompletableFuture<Object> cf4=CompletableFuture.anyOf(cf,cf2,cf3).whenComplete((a,b)->{
if(b!=null){
log.info("cf4执行开始,a={},b={}",a,b.getMessage());
}else{
log.info("cf4执行开始,a={}",a);
}
});
log.info("cf4执行结果={}",cf4.get());
TimeUnit.SECONDS.sleep(10);
}
运行结果
CompletableFuture默认使用ForkJoinPool.commonPool()线程池,如果机器是单核的,则默认使用ThreadPerTaskExecutor,该类是一个内部类,每次执行execute都会创建一个新线程