目录
一、CompletionService
1. 原理
内部通过阻塞队列+FutureTask,实现了任务先完成可优先获取到,即结果按照完成的先后顺序排序。内部有一个先进先出的队列,用于保存已经执行完成的Future,通过调用它的take方法或者poll方法,可以获取到一个已经执行完成的Future,进而通过调用Future接口的实现类的get方法获取到最终结果。
2.应用场景
Callable + Future 可以实现多个Task并行执行,但是遇到前面的task执行较慢时,需要阻塞等待前面的task执行完才能获取到后面task的执行结果。
CompletionService的主要功能就是一边生成任务,一边获取任务的返回值。让两件事分开执行,任务之间不会互相阻塞,可以实现执行完的先获取结果,不在依赖任务顺序。
简单说一下就是:
1.当需要批量提交异步任务的时候建议你使用CompletionService。
2.CompletionService能够让异步任务的执行结果有序化。先执行完的先进入阻塞队列
3.线程池隔离。CompletionService支持自己创建线程池,这种隔离性能避免几个特别耗时的任务拖垮整个应用的风险。
3.使用案例
案例一:向不同电商平台询价,并保存
public class CompletionServiceDemo2 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
//创建线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
//创建 CompletionService
ExecutorCompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
//异步向电商S1询价
cs.submit(() -> getPriceByS1(2));
//异步向电商S2询价
cs.submit(() -> getPriceByS2(8));
//异步向电商S3询价
cs.submit(() -> getPriceByS3(4));
//将结果异步保存到数据库
for (int i = 0; i < 3; i++) {
Future<Integer> future = cs.take();
Integer result = future.get();
System.out.println("任务【" + result + "】完成");
executor.execute(() -> {
try {
save(result);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
while (true) {
if (executor.isTerminated()) {
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) / 1000 + " s");
break;
}
}
}
private static Integer getPriceByS2(int i) throws InterruptedException {
TimeUnit.SECONDS.sleep(i);
return i;
}
private static Integer getPriceByS1(int i) throws InterruptedException {
TimeUnit.SECONDS.sleep(i);
return i;
}
private static Integer getPriceByS3(int i) throws InterruptedException {
TimeUnit.SECONDS.sleep(i);
return i;
}
private static void save(Integer price) throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
System.out.println("保存价格:" + price);
}
}
执行结果:
任务【2】完成
保存价格:2
任务【4】完成
保存价格:4
任务【8】完成
保存价格:8
耗时:9 s
案例二:并行地调用多个服务,只要有一个成功就返回结果
public class CompletionServiceDemo3 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
//创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
//创建completionService
ExecutorCompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
//用于保存Future对象
List<Future<Integer>> futures = new ArrayList<>();
//提交异步任务,并保存 future到 futures
futures.add(cs.submit(() -> getPriceByS1(5)));
futures.add(cs.submit(() -> getPriceByS2(3)));
futures.add(cs.submit(() -> getPriceByS3(2)));
Integer result = null;
//获取最快返回的任务执行结果
try {
for (int i = 0; i < 3; i++) {
Future<Integer> future = cs.take();
//将有结果的任务从结果集删除
futures.remove(future);
result = future.get();
if (result != null) {
break;
}
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
//取消剩下的所有任务
for (Future<Integer> future : futures) {
future.cancel(true);
}
}
executor.shutdown();
while (true) {
if (executor.isTerminated()) {
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) / 1000 + " s");
break;
}
}
System.out.println("最终结果:" + result);
}
private static Integer getPriceByS2(int i) throws InterruptedException {
TimeUnit.SECONDS.sleep(i);
return i;
}
private static Integer getPriceByS1(int i) throws InterruptedException {
TimeUnit.SECONDS.sleep(i);
return i;
}
private static Integer getPriceByS3(int i) throws InterruptedException {
TimeUnit.SECONDS.sleep(i);
return i;
}
}
执行结果:
耗时:2 s
最终结果:2
案例三:(高德笔试题)多个任务并行执行,有一个任务执行失败了,任务就结束。要求:最快
没有找到参考答案,这个是我自己想的,我觉得应该是对的。如有不对或者更好的答案欢迎在评论区指正、赐教
简单说明一下:
关键字是指假设失败的任务。其他任务正常执行,当一个任务异常失败或者逻辑失败,程序立即结束。
public class QuickFailure {
public static void main(String[] args) {
long start = System.currentTimeMillis();
int random = new Random().nextInt(10);
System.out.println("关键字:" + random);
ExecutorService pools = Executors.newFixedThreadPool(5);
ExecutorCompletionService<Integer> service = new ExecutorCompletionService<>(pools);
List<Future<Integer>> futures = new ArrayList<>();
//创建多个任务,并添加到集合
for (int i = 0; i < 10; i++) {
int finalI = i;
Future<Integer> future = service.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("任务 " + finalI + "开始...");
TimeUnit.SECONDS.sleep(finalI);
if (finalI == random) {
System.out.println("任务失败!!!");
return -1;
} else {
return finalI;
}
}
});
futures.add(future);
}
//获取最快返回的任务结果
for (int i = 0; i < 10; i++) {
try {
Future<Integer> future = service.take();
//将有结果的任务从结果集中删除
futures.remove(future);
//查看结果是否失败
Integer result = future.get();
if (result == -1) {
//结果失败了,程序立即停止
System.out.println("任务【" + random + "】出现异常失败");
pools.shutdown();
break;
} else {
//结果成功了,继续获取其他任务结果
System.out.println("任务【" + result + "】完成。");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//取消所有剩下的任务
for (Future<Integer> future : futures) {
future.cancel(true);
}
while (true) {
if (pools.isTerminated()) {
long end = System.currentTimeMillis();
System.out.println("程序结束,耗时:" + (end - start) / 1000 + " s");
break;
}
}
}
}
执行结果:
关键字:5
任务 0开始…
任务 1开始…
任务 2开始…
任务 3开始…
任务 5开始…
任务 4开始…
任务【0】完成。
任务 6开始…
任务【1】完成。
任务 7开始…
任务【2】完成。
任务 8开始…
任务【3】完成。
任务 9开始…
任务【4】完成。
任务失败!!!
任务【5】出现异常失败
程序结束,耗时:5 s
以上结果发现,任务5是那个注定失败的任务。任务5之前的任务按时完成,当任务5执行失败了,即便已经提交的其他任务未执行,程序也按要求立即退出。
二、CompletableFuture
1.应用场景
a.依赖关系
- thenApply() 把前面异步任务的结果,交给后面的Function
- thenCompose()用来连接两个有依赖关系的任务,结果由第二个任务返回
b.聚合关系(and)
- thenCombine:任务合并,有返回值。
- thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值。
- runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable)。
c.聚合关系(or)
- applyToEither:两个任务谁执行的快,就使用那一个结果,有返回值。
- acceptEither: 两个任务谁执行的快,就消耗那一个结果,无返回值。
- runAfterEither: 任意一个任务执行完成,进行下一步操作(Runnable)。
d.并行执行
- CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture并行执行。
2.详解
a.创建异步操作
public class CompletableFutureDemo1 {
public static void main(String[] args) {
Runnable runnable = () -> {
System.out.println("执行无返回结果的任务");
};
CompletableFuture.runAsync(runnable);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("执行有返回值的异步任务");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello world";
});
String result = null;
try {
result = future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println(result);
}
}
执行结果:
执行无返回结果的任务
执行有返回值的异步任务
hello world
b.结果处理
public class CompletableFutureDemo2 {
static ExecutorService pool1 = Executors.newFixedThreadPool(3);
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("thread name:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (new Random().nextInt(10) % 2 == 0) {
int i = 12 / 0;
}
System.out.println("执行结束!");
return "test";
}, pool1);
future.whenCompleteAsync(new BiConsumer<String, Throwable>() {
@Override
public void accept(String s, Throwable throwable) {
System.out.println("thread name:" + Thread.currentThread().getName());
System.out.println(s + " 执行完成!");
}
});
future.exceptionally(new Function<Throwable, String>() {
@Override
public String apply(Throwable throwable) {
System.out.println("执行失败:" + throwable.getMessage());
return "异常xxx";
}
});
new Scanner(System.in).nextLine();
}
}
执行结果失败:
thread name:pool-1-thread-1
执行失败:java.lang.ArithmeticException: / by zero
thread name:ForkJoinPool.commonPool-worker-9
null 执行完成!
========================================================
执行结果成功:
thread name:pool-1-thread-1
执行结束!
thread name:ForkJoinPool.commonPool-worker-9
test 执行完成!
c.结果转换
public class CompletableFutureDemo4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int result = new Random().nextInt(30);
System.out.println("第一阶段:" + result);
return result;
}
}).thenCompose(new Function<Integer, CompletionStage<Integer>>() {
@Override
public CompletionStage<Integer> apply(Integer param) {
return CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = param * 2;
System.out.println("第二阶段:" + number);
return number;
}
});
}
});
System.out.println("最终结果:" + future.get());
}
}
执行结果:
第一阶段:2
第二阶段:4
最终结果:4
d.结果消费
没有返回值,只对上一个结果处理
public class CompletableFutureDemo6 {
public static void main(String[] args) {
//thenAccept();
//thenAcceptBoth();
thenRun();
}
/**
* 不关心结果,只对结果执行Action。
* 与thenAccept不同的是,thenRun会在上一阶段 CompletionFuture 计算完成的时候执行一个Runnable,
* Runnable 并不使用该CompletableFuture计算结果。
*/
private static void thenRun() {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
int number = new Random().nextInt(10);
System.out.println("第一阶段:" + number);
return number;
}).thenRun(() -> {
System.out.println("thenRun 执行");
});
try {
System.out.println("最终结果:" + future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
/**
* 对两个结果进行消费
*/
private static void thenAcceptBoth() {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(3) + 1;
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一阶段:" + number);
return number;
}
});
CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(new Supplier<Object>() {
@Override
public Object get() {
int number = new Random().nextInt(3) + 1;
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二阶段:" + number);
return number;
}
});
future1.thenAcceptBoth(future2, new BiConsumer<Integer, Object>() {
@Override
public void accept(Integer x, Object y) {
System.out.println("最终结果:" + (x + (int) y));
}
}).join();
}
/**
* 对单个结果进行消费
*/
private static void thenAccept() {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
int number = new Random().nextInt(10);
System.out.println("第一阶段:" + number);
return number;
}).thenAccept(number -> {
try {
Thread.sleep(5000);
System.out.println("第二阶段:" + number * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
try {
System.out.println("最终结果:" + future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
e.结果组合
public class CompletableFutureDemo7 {
public static void main(String[] args) {
thenCombine();
//thenCombineAsync();
}
private static void thenCombineAsync(){
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
int number = new Random().nextInt(10);
System.out.println("第一阶段:" + number);
return number;
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(10);
System.out.println("第二阶段:" + number);
return number;
}
});
CompletableFuture<Integer> result = future1.thenCombineAsync(future2, new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer x, Integer y) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return x + y;
}
});
try {
System.out.println("最终结果:" + result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("end...");
}
/**
* 合并两个线程任务的结果,并进一步处理
*/
private static void thenCombine() {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
int number = new Random().nextInt(10);
System.out.println("第一阶段:" + number);
return number;
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(10);
System.out.println("第二阶段:" + number);
return number;
}
});
CompletableFuture<Integer> result = future1.thenCombineAsync(future2, new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer x, Integer y) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return x + y;
}
});
try {
System.out.println("最终结果:" + result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("end...");
}
}
f.任务交互
public class CompletableFutureDemo8 {
public static void main(String[] args) {
//applyToEither();
//acceptEither();
//runAfterEither();
//runAfterBoth();
//anyOf();
allOf();
}
/**
* 用来实现多个CompletableFuture的同时返回
*/
private static void allOf() {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future1完成!");
return "future1完成!";
}
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
System.out.println("future2完成!");
return "future2完成!";
}
});
CompletableFuture<Void> combineFuture = CompletableFuture.allOf(future1, future2);
try {
combineFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("future1: " + future1.isDone() + ", future2: " + future2.isDone());
try {
System.out.println("future1 = " + future1.get() + "future2 = " + future2.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
/**
* anyOf方法的参数时多个给定的CompletableFuture,当其中的任何一个完成时,方法返回这个CompletableFuture
*/
private static void anyOf() {
Random random = new Random();
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
TimeUnit.SECONDS.sleep(random.nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello";
}
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
TimeUnit.SECONDS.sleep(random.nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "world";
}
});
CompletableFuture<Object> result = CompletableFuture.anyOf(future1, future2);
try {
System.out.println(result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
/**
* 两个线程任务相比较,两个全部执行完成,才进行下一步操作,不关心运行结果
*/
private static void runAfterBoth() {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一阶段:1");
return 1;
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二阶段:2");
return 2;
}
});
future1.runAfterBoth(future2, new Runnable() {
@Override
public void run() {
System.out.println("上面两个任务都执行完成了");
}
}).join();
}
/**
* 两个线程任务比较,有任何一个执行完成,就进行下一步操作,不关心运行结果。
*/
private static void runAfterEither() {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(5);
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一阶段:" + number);
return number;
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(5);
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二阶段:" + number);
return number;
}
});
future1.runAfterEither(future2, new Runnable() {
@Override
public void run() {
System.out.println("已经有一个任务完成了");
}
}).join();
}
/**
* 两个线程任务相比较,先获得执行结果的,就对该结果进行下一步的消费操作。无返回值
*/
private static void acceptEither() {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(10);
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一阶段:" + number);
return number;
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(10);
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二阶段:" + number);
return number;
}
});
future1.acceptEither(future2, new Consumer<Integer>() {
@Override
public void accept(Integer number) {
System.out.println("最快结果:" + number);
}
}).join();
}
/**
* 两个线程任务相比较,先获得执行结果的,就对该结果进行下一步的转化操作。有返回值
*/
private static void applyToEither() {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(10);
System.out.println("第一阶段start:" + number);
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一阶段end:" + number);
return number;
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
int number = new Random().nextInt(10);
System.out.println("第二阶段start:" + number);
try {
TimeUnit.SECONDS.sleep(number);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二阶段end: " + number);
return number;
}
});
future1.applyToEither(future2, new Function<Integer, String>() {
@Override
public String apply(Integer number) {
System.out.println("最快结果:" + number);
return number * 2 + "";
}
}).join();
}
}
3.使用案例
烧水泡茶
对于烧水泡茶这个程序,一种最优的分工方案:用两个线程 T1 和 T2 来完成烧水泡茶程序,
T1 负责洗水壶、烧开水、泡茶这三道工序,T2 负责洗茶壶、洗茶杯、拿茶叶三道工序,其中
T1 在执行泡茶这道工序时需要等待 T2 完成拿茶叶的工序。
- 基于Future实现
public class MakeTea {
private static void doFuture() {
FutureTask<String> ft2 = new FutureTask<>(new Task2());
FutureTask<String> ft1 = new FutureTask<>(new Task1(ft2));
//线程t1执行任务ft1
Thread t1 = new Thread(ft1);
t1.start();
//线程t2执行任务ft2
Thread t2 = new Thread(ft2);
t2.start();
//等待线程t1执行的结果
try {
System.out.println(ft1.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
/**
* 需要执行:洗水壶 -> 烧开水 -> 泡茶(需要等待 task2送茶叶)
*/
private static class Task1 implements Callable<String> {
FutureTask<String> ft2;
public Task1(FutureTask<String> ft2) {
this.ft2 = ft2;
}
@Override
public String call() throws Exception {
System.out.println("t1: 洗水壶。。。");
TimeUnit.SECONDS.sleep(1);
System.out.println("t1: 烧开水。。。");
TimeUnit.SECONDS.sleep(15);
//获取t2线程送来的茶叶
String tea = ft2.get();
System.out.println("t1: 拿到茶叶【" + tea + "】");
System.out.println("t1: 泡茶。。。");
TimeUnit.SECONDS.sleep(3);
return "上茶【" + tea + "】";
}
}
/**
* 需要执行:洗茶壶 -> 洗茶杯 -> 拿茶叶
*/
private static class Task2 implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("t2: 洗茶壶。。。");
TimeUnit.SECONDS.sleep(1);
System.out.println("t2: 洗茶杯。。。");
TimeUnit.SECONDS.sleep(2);
System.out.println("t2: 拿茶叶。。。");
TimeUnit.SECONDS.sleep(1);
return "龙井";
}
}
}
执行结果:
t1: 洗水壶。。。
t2: 洗茶壶。。。
t2: 洗茶杯。。。
t1: 烧开水。。。
t2: 拿茶叶。。。
t1: 拿到茶叶【龙井】
t1: 泡茶。。。
上茶【龙井】
- 基于CompletableFuture实现
public class MakeTea {
private static void doCompletableFuture() {
CompletableFuture<Void> ft1 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
try {
System.out.println("t1: 洗水壶。。。");
TimeUnit.SECONDS.sleep(1);
System.out.println("t1: 烧开水。。。");
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
CompletableFuture<String> ft2 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
System.out.println("t2: 洗茶壶。。。");
TimeUnit.SECONDS.sleep(1);
System.out.println("t2: 洗茶杯。。。");
TimeUnit.SECONDS.sleep(2);
System.out.println("t2: 拿茶叶。。。");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "龙井";
}
});
//任务3: 任务1和任务2都完成以后执行:泡茶
CompletableFuture<String> ft3 = ft1.thenCombine(ft2, new BiFunction<Void, String, String>() {
@Override
public String apply(Void unused, String tea) {
System.out.println("t1: 拿到茶叶【" + tea + "】");
System.out.println("t1: 泡茶。。。");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "上茶【" + tea + "】";
}
});
//等待任务3的执行结果
System.out.println(ft3.join());
}
}
执行结果:
t1: 洗水壶。。。
t2: 洗茶壶。。。
t2: 洗茶杯。。。
t1: 烧开水。。。
t2: 拿茶叶。。。
t1: 拿到茶叶【龙井】
t1: 泡茶。。。
上茶【龙井】