前言
CompletableFuture是JDK1.8的特性,用到了异步IO多路复用技术,配合线程池使用提高服务QPS。
一、上代码
TestCompletableFuture.java
package thread;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;
/**
* Create by zjg on 2023/4/28
*/
public class TestCompletableFuture {
private static ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String args[]) throws ExecutionException, InterruptedException {
try {
supplyAsync();
System.out.println("-----方法分隔符-----");
runAsync();
}catch (Exception e){
e.printStackTrace();
}finally {
shutdown();
}
}
public static void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> cfs1 = CompletableFuture.supplyAsync(() -> {//Supplier,有返回值
System.out.println("cfs1:"+Thread.currentThread().getName() + "-start");//默认线程池ForkJoinPool
try {
Thread.sleep(2000);//演示anyOf
} catch (InterruptedException e) {
e.printStackTrace();
}
//throw new RuntimeException("ex");
return "Hello CompletableFuture1!";
});
CompletableFuture<String> cfs2 = CompletableFuture.supplyAsync(()->{
System.out.println("cfs2:"+Thread.currentThread().getName()+"-start");//自定义线程池(可控)
return "Hello CompletableFuture2!";
},executorService);
handle(cfs1,cfs2);
}
public static void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<Void> cfs1 = CompletableFuture.runAsync(()->{//Runnable,无返回值
System.out.println("cfs1:"+Thread.currentThread().getName() + "-start");//默认线程池ForkJoinPool
try {
Thread.sleep(2000);//演示anyOf
} catch (InterruptedException e) {
e.printStackTrace();
}
//throw new RuntimeException("ex");
});
CompletableFuture<Void> cfs2 = CompletableFuture.runAsync(()->{
System.out.println("cfs2:"+Thread.currentThread().getName()+"-start");//自定义线程池(可控)
},executorService);
handle(cfs1,cfs2);
}
public static void handle(CompletableFuture<?>... cfs) throws ExecutionException, InterruptedException {
System.out.println();
String s = CompletableFuture.anyOf(cfs).handle((res, ex) -> {
if(Optional.ofNullable(res).isPresent()){
System.out.println(res);
}
if(Optional.ofNullable(ex).isPresent()){
System.out.println(ex);
}
isDoneOut(cfs);
return "1和2其中一个处理完成";
}).get();
System.out.println(s);
System.out.println();
String cfs1Res = cfs[0].handleAsync((res, ex) -> {
if(ex!=null){
System.out.println("cfs1:发生异常:" + ex.getMessage());
return "500";
}
System.out.println("cfs1:处理结果:"+res);
return "200";
}).get();
System.out.println("cfs1:状态码:"+cfs1Res);
System.out.println();
String s1 = CompletableFuture.allOf(cfs).handle((res, ex) -> {
if (Optional.ofNullable(res).isPresent()) {
System.out.println(res);
}
if (Optional.ofNullable(ex).isPresent()) {
System.out.println(ex);
}
getOut(cfs);
isDoneOut(cfs);
return "1和2全部处理完成";
}).get();
System.out.println(s1);
System.out.println("success");
}
public static void isDoneOut(CompletableFuture<?>... cfs){
Stream.iterate(0, i -> i + 1).limit(cfs.length).forEach(index -> {
System.out.println("cfs" + (index+1)+":"+ cfs[index].isDone());
});
}
public static void getOut(CompletableFuture<?>... cfs){
Stream.iterate(0, i -> i + 1).limit(cfs.length).forEach(index -> {
try {
System.out.println("cfs" + (index+1)+":"+ cfs[index].get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
}
public static void shutdown(){
executorService.shutdown();
}
}
二、输出
cfs1:ForkJoinPool.commonPool-worker-1-start
cfs2:pool-1-thread-1-start
Hello CompletableFuture2!
cfs1:false
cfs2:true
1和2其中一个处理完成
cfs1:处理结果:Hello CompletableFuture1!
cfs1:状态码:200
cfs1:Hello CompletableFuture1!
cfs2:Hello CompletableFuture2!
cfs1:true
cfs2:true
1和2全部处理完成
success
-----方法分隔符-----
cfs1:ForkJoinPool.commonPool-worker-2-start
cfs2:pool-1-thread-2-start
cfs1:false
cfs2:true
1和2其中一个处理完成
cfs1:处理结果:null
cfs1:状态码:200
cfs1:null
cfs2:null
cfs1:true
cfs2:true
1和2全部处理完成
success
总结
supplyAsync
和runAsync
两个方法最大的区别是,前者回调返回值是一个泛型,后者泛型为Void
会get到null
值,所以具体使用哪个方法看情况而定。
回到顶部