使用线程池执行任务没法直接对多个任务进行链式、组合等处理,或者说实现起来比较麻烦需要借助并发工具类才能完成。
CompletableFuture实现了对任务编排的能力。借助这项能力,可以轻松地组织不同任务的运行顺序、规则以及方式。从某种程度上说,这
项能力是它的核心能力。
无返回值的方法:
// 无返回值方法
runAsync(runnable): CompletableFuture以异步方式启动一个任务并在默认的线程池(ForkJoinPool)执行
runAsync(runnable,executor):CompletableFuture 以异步方式启动一个任务并在指定的线程池(executor)执行
代码演示:
publicstaticvoidmain(String[] args) throwsIOException, ExecutionException, InterruptedException {
runAsyncTest01() ;
System.out.println("业务线程执行完毕了...");
System.in.read() ; // 让JVM不要立即退出
}
publicstaticvoidrunAsyncTest01() {
CompletableFuture.runAsync(() ->System.out.println(Thread.currentThread() +"执行了一个任务")) ;
}
publicstaticvoidrunAsyncTest02() {
CompletableFuture.runAsync(() ->System.out.println(Thread.currentThread() +"执行了一个任务") , service) ;
}
有返回值方法:
// 有返回值方法
supplyAsync(supplier): CompletableFuture 以异步方式启动一个任务并在默认的线程池(ForkJoinPool)执行。
supplyAsync(supplier,executor):CompletableFuture 以异步方式启动一个任务并在指定的线程池(executor)执行。
代码演示:
publicstaticvoidsupplyAsyncTest02() throwsExecutionException, InterruptedException {
CompletableFuturesupplyAsync=CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10;
},service);
Integercount=supplyAsync.get();
System.out.println(count);
}
publicstaticvoidsupplyAsyncTest01() throwsExecutionException, InterruptedException {
CompletableFuturesupplyAsync=CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10;
});
Integercount=supplyAsync.get(); // 获取异步线程执行结果
System.out.println(count);
}
可以在任务执行完毕以后(不论是正常执行完毕还是出现异常)执行某一个操作。
正常完成:whenComplete返回结果和上级任务一致,异常为null;
出现异常:whenComplete返回结果为null,异常为上级任务的异常;
相关方法:
whenComplete(action) 使用当前线程执行一个动作,不开启额外的线程
whenCompleteAsync(action) 在默认的线程池中开启一个线程执行该动作
whenCompleteAsync(action, executor) 在指定的线程池中开启一个线程执行该动作
注意:如果上一次任务执行完毕以后产生了异常,那么此时在调用get方法获取结果的时候就会抛出异常。
publicstaticvoidwhenCompleteTest01() throwsExecutionException, InterruptedException {
/**
* result参数表示的是上一次任务执行完成以后的结果
* e:表示的是异常对象
*/
CompletableFuturesupplyAsync=CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10;
},service).whenComplete((result , e) -> { // 使用main线程执行当前任务
if(e==null) {
System.out.println(Thread.currentThread() +"上一次任务正常执行完成了,任务的返回结果为:"+result);
}else {
System.out.println(Thread.currentThread() +"上一次任务执行时产生了异常,任务的返回结果为:"+result);
}
});
Integerinteger=supplyAsync.get(); // 获取异步任务的结果,如果whenComplete上一次执行的产生异常了,那么在调用该方法的时候就会报错
System.out.println(integer);
}
publicstaticvoidwhenCompleteTest02() throwsExecutionException, InterruptedException {
/**
* result参数表示的是上一次任务执行完成以后的结果
* e:表示的是异常对象
*/
CompletableFuturesupplyAsync=CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10/0 ;
},service).whenComplete((result , e) -> {
if(e==null) {
System.out.println(Thread.currentThread() +"上一次任务正常执行完成了,任务的返回结果为:"+result);
}else {
System.out.println(Thread.currentThread() +"上一次任务执行时产生了异常,任务的返回结果为:"+result);
}
}).exceptionally((e) -> { // 配合exceptionally方法可以在产生异常以后返回一个默认值。
System.out.println(e);
return20 ;
});
Integerinteger=supplyAsync.get();
System.out.println(integer);
}
相关方法:
// 无法获取到上一次任务的执行结果
thenRun(runnable): 接下来跑一个任务,以当前线程作为跑任务的线程,不开额外的异步线程
thenRunAsync(runnable): 接下来跑一个任务,用默认线程池新开一个异步线程
thenRunAsync(runnable,executor): 接下来跑一个任务,用指定线程池新开一个异步线程
上述方法和whenComplete比较区别:thenXXX无法获取到上一个任务产生的异常。当上一个任务执行完毕以后产生了异常,那么该任务无法执行。
代码演示:
publicstaticvoidthenRunAsyncTest01() {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10 ;
},service).thenRun(() -> {
System.out.println(Thread.currentThread() +"---上一个任务执行完毕了,执行该任务");
});
}
相关方法:
thenAccept(consumer): 接下来跑一个任务,接受到上次的结果,以当前线程作为跑任务的线程,不开额外的异步线程
thenAcceptAsync(consumer): 接下来跑一个任务,接受到上次的结果,用默认线程池新开一个异步线程
thenAcceptAsync(consumer,executor) 接下来跑一个任务,接受到上次的结果,用指定线程池新开一个异步线程
代码演示:
publicstaticvoidthenAcceptTest01() {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10 ;
},service).thenAccept((result) ->System.out.println(result*10));
}
相关方法:
thenApply(function) 接下来跑一个任务,接受到上次的结果,并且返回一个新的结果,以当前线程作为跑任务的线程,不开额外的异步线程
thenApplyAsync(function) 接下来跑一个任务,接受到上次的结果,并且返回一个新的结果,用默认线程池新开一个异步线程
thenApplyAsync(function, executor)接下来跑一个任务,接受到上次的结果,并且返回一个新的结果,用指定线程池新开一个异步线程
代码演示:
publicstaticvoidthenApplyAsyncTest01() throwsExecutionException, InterruptedException {
Integercount=CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread());
return10;
}, service).thenApplyAsync((result) -> {
System.out.println(Thread.currentThread() +"---"+result*10);
returnresult*2;
}).get(); // 获取最终的执行结果
System.out.println(count);
}
需求:在控制台按照顺序输出"haha"、"hehe"、"heihei"
publicstaticvoidcompletableTash() throwsExecutionException, InterruptedException {
CompletableFuture.runAsync(() ->System.out.println("haha")).thenRun(() ->System.out.println("hehe"))
.thenRun(() ->System.out.println("heihei")) ;
}
相关方法:
CompletableFuture
CompletableFuture
CompletableFuture
代码演示:
privatestaticvoidallOf() throwsExecutionException, InterruptedException {
CompletableFuturecompletableFuture1=CompletableFuture.runAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
System.out.println("任务1执行完毕");
});
CompletableFuturecompletableFuture2=CompletableFuture.runAsync(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
System.out.println("任务2执行完毕");
});
// CompletableFuture.anyOf(completableFuture1 , completableFuture2).join() ; // 调用get方法或者join方法阻塞当前线程
// CompletableFuture.allOf(completableFuture1 , completableFuture2).join() ;
completableFuture1.runAfterBoth(completableFuture2 , () ->System.out.println("任务三执行")) ;
System.out.println("heheihei");
}