completablefuture用法详解【快速入门,没有技巧,全是实操】_程序桃子的博客-爱代码爱编程
前置知识
在开始本篇内容前我希望读者已经了解Java多线程的概念及其基本知识。
Completable常见方法
首先自定义一个线程池用于任务提交
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
10,
20,
20,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());
// 文中用到的睡眠方法
public static void sleep(int i) {
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* submit(Callable<T> task): 将任务提交给线程池,返回值为Future对象
*/
@Test
public void test1() throws ExecutionException, InterruptedException {
Future<String> submit = poolExecutor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
return "hello threadPool~";
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println("threadPool result: " + submit.get());
System.out.println("main endTime: " + System.currentTimeMillis());
}
/**
* execute(Runnable command): 将任务提交给线程池,没有返回值
*/
@Test
public void test2() {
poolExecutor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
// return "hello threadPool~"; 报错
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println("main endTime: " + System.currentTimeMillis());
Sleeper.sleep(2);
}
submit:
main startTime: 1664988253919
pool-1-thread-1 startTime: 1664988253919
pool-1-thread-1 endTime: 1664988254931
threadPool result: hello threadPool~
main endTime: 1664988254931
execute:main startTime: 1664988269428
main endTime: 1664988269428
pool-1-thread-1 startTime: 1664988269428
pool-1-thread-1 endTime: 1664988270430
/**
* runAsync(Runnable runnable, Executor executor)
* 类似于 Test2,线程池的 execute 方法
* <p>
* supplyAsync(Supplier<U> supplier, Executor executor)
* 类似于 Test1,线程池的 submit 方法
*/
@Test
public void test3() throws ExecutionException, InterruptedException {
CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
}, poolExecutor);
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println("main endTime: " + System.currentTimeMillis());
Sleeper.sleep(2);
System.out.println("===============supplyAsync==============");
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
return "hello supplyAsync~";
}, poolExecutor);
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println(future.get());
System.out.println("main endTime: " + System.currentTimeMillis());
}
main startTime: 1664988310101
main endTime: 1664988310101
pool-1-thread-1 startTime: 1664988310101
pool-1-thread-1 endTime: 1664988311111
===============supplyAsync==============
main startTime: 1664988312104
pool-1-thread-2 startTime: 1664988312104
pool-1-thread-2 endTime: 1664988313116
hello supplyAsync~
main endTime: 1664988313116
/**
* thenApply(Function<? super T,? extends U> fn)
* thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
* 将第一个future对象的返回值传入第二个任务中,两者不同之处在于前者两个任务运行在一个线程,而后者不是。
*/
@Test
public void test4() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
return "hello supplyAsync~";
}, poolExecutor);
CompletableFuture<String> future2 = future.thenApply((e) -> {
System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
return e + " hello!I am job2";
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println(future2.get());
System.out.println("main endTime: " + System.currentTimeMillis());
}
pool-1-thread-1 startTime: 1664988334854
main startTime: 1664988334855
pool-1-thread-1 endTime: 1664988335863
pool-1-thread-1 startTime: 1664988335863
pool-1-thread-1 endTime: 1664988336866
hello supplyAsync~ hello!I am job2
main endTime: 1664988336866
/**
* thenAccept(Consumer<? super T> action):
* 接收一个参数,没有返回值
* thenRun(Runnable action):
* 不接收参数,没有返回值
*/
@Test
public void test5() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "hello supplyAsync~";
}, poolExecutor);
future.thenAccept((e) -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
}).thenRun(() -> {
System.out.println(Thread.currentThread().getName() + " job3 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job3 endTime: " + System.currentTimeMillis());
});
System.out.println("main startTime: " + System.currentTimeMillis());
Sleeper.sleep(5);
System.out.println("main endTime: " + System.currentTimeMillis());
}
pool-1-thread-1 job1 startTime: 1664988358769
main startTime: 1664988358770
pool-1-thread-1 job1 endTime: 1664988359776
pool-1-thread-1 job2 startTime: 1664988359776
pool-1-thread-1 job2 endTime: 1664988360785
pool-1-thread-1 job3 startTime: 1664988360785
pool-1-thread-1 job3 endTime: 1664988361800
main endTime: 1664988363772
/**
* exceptionally(Function<Throwable, ? extends T> fn)
* 若Job1有异常则执行Job2
*/
@Test
public void test6() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
try {
throw new Exception("exception...");
} catch (Exception e) {
e.printStackTrace();
return "exception...";
}
}, poolExecutor);
CompletableFuture<String> exceptionally = future.exceptionally((exception) -> {
System.out.println(Thread.currentThread().getName() + " exception startTime: " + System.currentTimeMillis());
return exception.getMessage();
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println(exceptionally.get());
System.out.println("main endTime: " + System.currentTimeMillis());
}
pool-1-thread-1 job1 startTime: 1664988463352
main startTime: 1664988463353
java.lang.Exception: exception...
at com.shuttle.day03.completablefuture.CompletableFutureTest.lambda$test6$9(CompletableFutureTest.java:155)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
exception...
main endTime: 1664988464366
/**
* whenComplete(BiConsumer<? super T, ? super Throwable> action)
* 当 job1 完成时执行 job2 传入参数为 (job1返回值, job1抛出异常【若没有异常则为null】)
*/
@Test
public void test7() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
// try {
// throw new Exception("exception...");
// } catch (Exception e) {
// e.printStackTrace();
// return "exception...";
// }
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "hello supplyAsync~";
}, poolExecutor);
CompletableFuture<String> job2 = future.whenComplete((result, exception) -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
if (exception != null) {
exception.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println(job2.get());
System.out.println("main endTime: " + System.currentTimeMillis());
}
pool-1-thread-1 job1 startTime: 1664988554460
main startTime: 1664988554460
pool-1-thread-1 job1 endTime: 1664988555477
pool-1-thread-1 job2 startTime: 1664988555477
pool-1-thread-1 job2 endTime: 1664988556488
hello supplyAsync~
main endTime: 1664988556488
/**
* handle(BiFunction<? super T, Throwable, ? extends U> fn)
* 和whenComplete基本一致,但handle有返回值
*/
@Test
public void test8() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
// try {
// throw new Exception("exception...");
// } catch (Exception e) {
// e.printStackTrace();
// return "exception...";
// }
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "hello supplyAsync~";
}, poolExecutor);
CompletableFuture<String> job2 = future.handle((result, exception) -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
if (exception != null) {
exception.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
return result + "hello handle~";
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println(job2.get());
System.out.println("main endTime: " + System.currentTimeMillis());
}
pool-1-thread-1 job1 startTime: 1664988612783
main startTime: 1664988612783
pool-1-thread-1 job1 endTime: 1664988613786
pool-1-thread-1 job2 startTime: 1664988613786
pool-1-thread-1 job2 endTime: 1664988614793
hello supplyAsync~hello handle~
main endTime: 1664988614793
/**
* thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
* thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)
* runAfterBoth(CompletionStage<?> other, Runnable action)
* <p>
* job1.thenCombine(job2) 当job1和job2都完成时执行job3 可接收job1 和 job2 的返回值,并有新的返回值
* thenAcceptBoth与thenCombine的区别就是没有返回值
* runAfterBoth没有入参也没有返回值
*/
@Test
public void test9() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "helloA supplyAsync~";
}, poolExecutor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
return "helloB supplyAsync~";
}, poolExecutor);
CompletableFuture<String> future3 = future.thenCombine(future2, (a, b) -> {
System.out.println(Thread.currentThread().getName() + " thenCombine startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " thenCombine endTime: " + System.currentTimeMillis());
return a + b;
});
future.thenAcceptBoth(future2, (a, b) -> {
System.out.println(Thread.currentThread().getName() + " thenAcceptBoth startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " thenAcceptBoth endTime: " + System.currentTimeMillis());
});
future.runAfterBoth(future2, () -> {
System.out.println(Thread.currentThread().getName() + " runAfterBoth startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " runAfterBoth endTime: " + System.currentTimeMillis());
});
System.out.println("main startTime: " + System.currentTimeMillis());
System.out.println(future3.get());
System.out.println("main endTime: " + System.currentTimeMillis());
Sleeper.sleep(5);
}
pool-1-thread-1 job1 startTime: 1664988653498
pool-1-thread-2 job2 startTime: 1664988653498
main startTime: 1664988653500
pool-1-thread-1 job1 endTime: 1664988654507
pool-1-thread-2 job2 endTime: 1664988654507
pool-1-thread-2 runAfterBoth startTime: 1664988654507
pool-1-thread-2 runAfterBoth endTime: 1664988655522
pool-1-thread-2 thenAcceptBoth startTime: 1664988655522
pool-1-thread-2 thenAcceptBoth endTime: 1664988656527
pool-1-thread-2 thenCombine startTime: 1664988656527
pool-1-thread-2 thenCombine endTime: 1664988657541
helloA supplyAsync~helloB supplyAsync~
main endTime: 1664988657544
/**
* applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
* acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
* runAfterEither(CompletionStage<?> other, Runnable action)
* <p>
* job1.applyToEither(job2) 当job1 和 job2 之间有一个完成任务就执行job3【接受其中的返回值】
* acceptEither与applyToEither的区别就是没有返回值
* runAfterEither没有入参也没有返回值
*/
@Test
public void test10() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "helloA supplyAsync~";
}, poolExecutor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(2);
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
return "helloB supplyAsync~";
}, poolExecutor);
CompletableFuture<String> stringCompletableFuture = future.applyToEither(future2, (a) -> {
System.out.println(Thread.currentThread().getName() + " applyToEither startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " applyToEither endTime: " + System.currentTimeMillis());
return a + " applyToEither";
});
future.acceptEither(future2, (a) -> {
System.out.println(Thread.currentThread().getName() + " acceptEither startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " acceptEither endTime: " + System.currentTimeMillis());
});
future.runAfterEither(future2, () -> {
System.out.println(Thread.currentThread().getName() + " runAfterEither startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " runAfterEither endTime: " + System.currentTimeMillis());
});
stringCompletableFuture.get();
Sleeper.sleep(5);
}
pool-1-thread-1 job1 startTime: 1664988743472
pool-1-thread-2 job2 startTime: 1664988743472
pool-1-thread-1 job1 endTime: 1664988744487
pool-1-thread-1 runAfterEither startTime: 1664988744487
pool-1-thread-2 job2 endTime: 1664988745482
pool-1-thread-2 acceptEither startTime: 1664988745482
pool-1-thread-1 runAfterEither endTime: 1664988745497
pool-1-thread-1 applyToEither startTime: 1664988745497
pool-1-thread-2 acceptEither endTime: 1664988746487
pool-1-thread-1 applyToEither endTime: 1664988746503
/**
* thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
* 在job1执行完成后执行job2,如果job2的返回值不为 null,则返回一个新的Completable对象
*/
@Test
public void test11() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "helloA supplyAsync~";
}, poolExecutor);
CompletableFuture<String> stringCompletableFuture = future.thenCompose((e) -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
return CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job3 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job3 endTime: " + System.currentTimeMillis());
return "hello thenCompose~";
});
});
System.out.println(stringCompletableFuture.get());
}
pool-1-thread-1 job1 startTime: 1664988778698
pool-1-thread-1 job1 endTime: 1664988779713
pool-1-thread-1 job2 startTime: 1664988779713
pool-1-thread-1 job2 endTime: 1664988780721
ForkJoinPool.commonPool-worker-9 job3 startTime: 1664988780722
ForkJoinPool.commonPool-worker-9 job3 endTime: 1664988781736
hello thenCompose~
/**
* allOf(CompletableFuture<?>... cfs): 所有任务执行完执行,没有返回值
* anyOf(CompletableFuture<?>... cfs): 任一任务执行完执行,有返回值【任务最快的那个】
*/
@Test
public void test12() throws ExecutionException, InterruptedException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
return "helloA supplyAsync~";
}, poolExecutor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
Sleeper.sleep(2);
System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
return "helloB supplyAsync~";
}, poolExecutor);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " job3 startTime: " + System.currentTimeMillis());
Sleeper.sleep(3);
System.out.println(Thread.currentThread().getName() + " job3 endTime: " + System.currentTimeMillis());
return "helloC supplyAsync~";
}, poolExecutor);
CompletableFuture<Void> completableFuture = CompletableFuture.allOf(future1, future2, future3).whenComplete((result, exception) -> {
System.out.println(Thread.currentThread().getName() + " allOf startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
if (exception != null) {
exception.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " allOf endTime: " + System.currentTimeMillis());
});
CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(future1, future2, future3).whenComplete((result, exception) -> {
System.out.println(Thread.currentThread().getName() + " anyOf startTime: " + System.currentTimeMillis());
Sleeper.sleep(1);
if (exception != null) {
exception.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " anyOf endTime: " + System.currentTimeMillis());
});
System.out.println("allOf " + completableFuture.get());
System.out.println("anyOf " + objectCompletableFuture.get());
}
pool-1-thread-1 job1 startTime: 1664988904061
pool-1-thread-2 job2 startTime: 1664988904062
pool-1-thread-3 job3 startTime: 1664988904062
pool-1-thread-1 job1 endTime: 1664988905066
pool-1-thread-1 anyOf startTime: 1664988905066
pool-1-thread-2 job2 endTime: 1664988906065
pool-1-thread-1 anyOf endTime: 1664988906081
pool-1-thread-3 job3 endTime: 1664988907072
pool-1-thread-3 allOf startTime: 1664988907072
pool-1-thread-3 allOf endTime: 1664988908079
allOf null
anyOf helloA supplyAsync~
啊!常见方法终于列得差不多了,虽然看起来代码很多,但是其中有很多是重复度比较高的部分,能看到这并且都能手敲下来的都是勇士。
现在我们一起来看看下面这个模拟的真实场景需求:
目前某公司网站首页全部加载需要超过 3 秒的时间,其中包括静态图片模块、实时播报模块、三级分类搜索模块等等。现需要将其优化为 1 秒以内【假设其中所有模块单独运行都不超过 1 秒】,请给出解决方案。
原始伪代码
/* 模拟展示静态图片 */
public void showPic() throws InterruptedException {
Thread.sleep(500);
}
/* 模拟实时轮播图 */
public void showLB() throws InterruptedException {
Thread.sleep(800);
}
/* 模拟三级分类搜索 */
public void threeSearch() throws InterruptedException {
Thread.sleep(900);
}
/* 模拟其它资源加载 */
public void other() throws InterruptedException {
Thread.sleep(1000);
}
public static void main(String[] args) throws InterruptedException {
CompletableFutureTest app = new CompletableFutureTest();
long startTime = System.currentTimeMillis();
// 展示静态图片
app.showPic();
// 实时轮播图
app.showLB();
// 三级分类搜索
app.threeSearch();
// 其它资源加载
app.other();
long endTime = System.currentTimeMillis();
System.out.println("网页加载完毕! 总耗时: " + (endTime - startTime) + " ms");
}
网页加载完毕! 总耗时: 3219 ms
下面我们用CompletableFuture对其进行优化
CompletableFutureTest app = new CompletableFutureTest();
long startTime = System.currentTimeMillis();
// 展示静态图片
CompletableFuture<Void> job1 = CompletableFuture.runAsync(() -> {
try {
app.showPic();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("静态图片加载完毕~");
});
// 实时轮播图
CompletableFuture<Void> job2 = CompletableFuture.runAsync(() -> {
try {
app.showLB();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("实时轮播图加载完毕~");
});
// 三级分类搜索
CompletableFuture<Void> job3 = CompletableFuture.runAsync(() -> {
try {
app.threeSearch();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("三级分类搜索加载完毕~");
});
// 其它资源加载
CompletableFuture<Void> job4 = CompletableFuture.runAsync(() -> {
try {
app.other();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("其它资源加载完毕~");
});
// 组合所有任务
CompletableFuture<Void> completableFuture = CompletableFuture.allOf(job1, job2, job3, job4).whenComplete((result, exception) -> {
if (exception != null) {
// 模拟中间出现异常
exception.printStackTrace();
}
});
// 阻塞等待所有任务完成,时间取决于耗时最长的那个
completableFuture.get();
long endTime = System.currentTimeMillis();
System.out.println("网页加载完毕! 总耗时: " + (endTime - startTime) + " ms");
静态图片加载完毕~
实时轮播图加载完毕~
三级分类搜索加载完毕~
其它资源加载完毕~
网页加载完毕! 总耗时: 1075 ms
上述仅仅只是模拟的一个非常简单的场景,模块之间没有相互依赖。CompletableFuture能做的事情可远远不止这些,例如一个模块需要依赖另一个模块的返回值,那么就可以使用thenApply【有返回值】或者thenAccept【无返回值】。
写在最后
CompletableFuture的出现为Java并发编程添加了新的思路,在此向 Doug Lea 大神致敬!不过在使用它的同时也要避免多线程带来的线程安全问题,希望大家有了足够的并发知识积累之后在实际工作中使用CompletableFuture,以免出现预期外的异常。
如果本篇内容对大家有帮助,希望多多支持哈~