CompletableFuture也是java1.8新特性之一,是JUC包下的工具类,主要用于异步编排获取结果
异步执行任务
supplyAsync() :异步开启一个任务,并且指定线程池,可以有返回数据
runAsync():异步开启一个任务,并且指定线程池,但是不允许有返回数据
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
//使用supplyAsync()执行一个任务,可以有返回值
CompletableFuture<String> task = CompletableFuture.supplyAsync(()->{
System.out.println("我开始执行任务了......."+Thread.currentThread().getName());
return "good";
},pool);
//可以拿到异步任务的执行结果
System.out.println(task.get());
//使用runAsync()执行一个任务,不能有返回值
CompletableFuture<Void> task1 = CompletableFuture.runAsync(()->{
System.out.println("我开始执行任务了......."+Thread.currentThread().getName());
},pool);
pool.shutdownNow();
}
任务编排
当我们有顺序执行任务的需求的时候,即这个任务需要上一个任务的结果等情况,需要进行编排
①thenApply(),thenAccept(),thenRun()
thenApply():有入参,有返回值,可获得前一个任务的返回值进行操作,并且可以返回数据
thenAccept():有入参,无返回值,可获得前一个任务的返回值进行操作,但是没有返回数据
thenRun():无入参,无返回值,不可获得前一个任务的返回值,也没有返回数据
ExecutorService pool = Executors.newFixedThreadPool(5);
//thenApply(),有入参,有返回值
CompletableFuture<String> task = CompletableFuture.supplyAsync(()->{
System.out.println("task任务一先执行"+Thread.currentThread().getName());
return "1";
},pool).thenApply(s -> {
System.out.println("前面任务的返回值:"+s);
System.out.println("task任务二后执行"+Thread.currentThread().getName());
return "2";
});
System.out.println(task.get());
//thenAccept(),有入参,无返回值
CompletableFuture<Void> task1 = CompletableFuture.supplyAsync(()->{
System.out.println("task1任务一先执行"+Thread.currentThread().getName());
return "1";
},pool).thenAccept(s -> {
System.out.println("前面任务的返回值:"+s);
System.out.println("task1任务二后执行"+Thread.currentThread().getName());
});
//thenRun(),无入参,无返回值
CompletableFuture<Void> task2 = CompletableFuture.supplyAsync(()->{
System.out.println("task2任务一先执行"+Thread.currentThread().getName());
return "1";
},pool).thenRun(() -> System.out.println("task2任务二后执行"+Thread.currentThread().getName()));
pool.shutdownNow();
②thenCombine()
thenCombine():有两个入参,再将并行任务1,2的结果进行统一处理计算
ExecutorService pool = Executors.newFixedThreadPool(4);
//任务1
CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"我先去1号目的地需要花费"+300+"块");
return 300;
},pool);
//任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"我再去2号目的地需要花费"+500+"块");
return 500;
},pool);
CompletableFuture<Integer> result = task1.thenCombine(task2, (r1, r2) -> {
System.out.println(Thread.currentThread().getName()+"最近计算出总费用"+(r1+r2));
return r1+r2;
});
③runAfterEither(),runAfterBoth()
runAfterEither():两个任务,但凡有一个任务执行完了,就会执行后续的代码
runAfterBoth():两个任务,两个任务都执行完了才会执行后续代码
ExecutorService pool = Executors.newFixedThreadPool(4);
CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"我先去1号目的地需要花费"+300+"块");
return 300;
},pool);
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"我再去2号目的地需要花费"+500+"块");
return 500;
},pool);
//有任何一个执行完就会执行后续代码
task1.runAfterEither(task2,()->{ System.out.println("!!!!!!!"); });
//两个都执行完才会执行后续代码
task1.runAfterBoth(task2,()->{ System.out.println("+++++++"); });
pool.shutdownNow();
④allOf(),anyOf()
allOf():
anyOf():
ExecutorService pool = Executors.newFixedThreadPool(4);
CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"我先去1号目的地需要花费"+300+"块");
return 300;
},pool);
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"我再去2号目的地需要花费"+500+"块");
for (int i = 0; i < 1000; i++) {
int x=0;
x+=i;
}
return 500;
},pool);
CompletableFuture<Integer> result = task1.thenCombine(task2, (r1, r2) -> {
System.out.println(Thread.currentThread().getName()+"最近计算出总费用"+(r1+r2));
return r1+r2;
});
//只有这两个任务全执行完才会往下执行主线程
CompletableFuture.allOf(task1,task2).join();
System.out.println("我是主线程");
pool.shutdownNow();
获取结果
get():阻塞等待结果
getNow():like获得现在的结果
停止任务
complete():直接让任务完成
cacel():如果任务还没开始/正在执行,则可以取消任务,设置取消标记为true。如果任务已经完成了,则设置取消标志为false
实战事例
public static void main(String[] args) throws ExecutionException, InterruptedException {
//获取服务器的核心数
int cores = Runtime.getRuntime().availableProcessors();
//自定义创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
cores+1, //核心线程数
cores+1, //最大线程数
0, //空闲线程存活时间
TimeUnit.SECONDS, //时间单位
new ArrayBlockingQueue<>(10), //任务等待队列
Executors.defaultThreadFactory(), //线程工厂
new ThreadPoolExecutor.AbortPolicy() //解决策略
);
//创建任务
CompletableFuture<String> task1 = CompletableFuture.supplyAsync(()->{
System.out.println("执行任务一........");
return "Task1 Sucess";
},threadPool);
CompletableFuture<String> task2 = CompletableFuture.supplyAsync(()->{
System.out.println("执行任务二........");
return "Task2 Sucess";
},threadPool);
CompletableFuture<String> task3 = CompletableFuture.supplyAsync(()->{
System.out.println("执行任务三........");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Task3 Sucess";
},threadPool);
//等待所有任务完成
CompletableFuture.allOf(task1, task2, task3).join();
//获取结果
String s1 = task1.get();
String s2 = task2.get();
String s3 = task3.get();
System.out.println(s1+s2+s3);
threadPool.shutdownNow();
}
项目中的使用场景