提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
如何使用CompletableFuture异步编程
例子
串行执行
public class Test1 {
public static void main(String[] args) {
Long start = System.currentTimeMillis();
task1();
task2();
Long end = System.currentTimeMillis();
System.out.println("执行时长------>"+ (end - start) / 1000.0 +"秒");
}
private static void task1() {
try {
Thread.sleep(5000);
System.out.println("任务1执行成功");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void task2() {
try {
Thread.sleep(3000);
System.out.println("任务2执行成功");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
-----------------------------------
任务1执行成功
任务2执行成功
执行时长------>8.014秒
-----------------------------------
CompletableFuture异步
public class Test1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long start = System.currentTimeMillis();
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 执行任务1 // supplyAsync 带返回值
CompletableFuture<String> comFeature1 = CompletableFuture.supplyAsync(()->{
task1();
return "task1Success";
}, executor);
// 执行任务2 // supplyAsync 带返回值
CompletableFuture<String> comFeature2 = CompletableFuture.supplyAsync(()->{
task2();
return "task2Success";
});
// 等待任务1和任务2执行完毕后,获取返回值 再执行后续操作
String join1 = comFeature1.get();
String join2 = comFeature2.get();
// runAsync 不带返回值
CompletableFuture<Void> feature3 = CompletableFuture.runAsync(() -> {
System.out.println("任务1返回----->"+join1);
System.out.println("任务2返回----->"+join2);
});
// 等待操作执行完成
feature3.get();
// 关闭线程池
executor.shutdown();
Long end = System.currentTimeMillis();
System.out.println("执行时长------>"+ (end - start) / 1000.0 +"秒");
}
private static void task1() {
try {
Thread.sleep(5000);
System.out.println("任务1执行成功");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void task2() {
try {
Thread.sleep(3000);
System.out.println("任务2执行成功");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
---------------------------------
任务2执行成功
任务1执行成功
任务1返回----->task1Success
任务2返回----->task2Success
执行时长------>5.048秒
---------------------------------
supplyAsync回调
回调函数方法,thenAppply(Function<T,R>)方法,该方法可以将任务执行完成之后,自动将结果获取,并对结果进行操作。转换后的结果可以交给主线程获取,也可以进一步转换。也就是说这个结果thenApply(Function<T,R>)是一个带返回值的回调方法
public class Test1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long start = System.currentTimeMillis();
// 执行任务1
CompletableFuture<String> comFeature1 = CompletableFuture.supplyAsync(()->{
task1();
return "task1Success";
});
// 执行任务2
CompletableFuture<String> comFeature2 = CompletableFuture.supplyAsync(()->{
task2();
return "task2Success";
}).thenApply(result->{
//等待任务1执行完成拿到返回值
String task1Str = comFeature1.join();
return result+"--"+task1Str;
});
// 等待操作执行完成
String result = comFeature2.join();
System.out.println("执行结果:-------------->"+result);
Long end = System.currentTimeMillis();
System.out.println("执行时长------>"+ (end - start) / 1000.0 +"秒");
}
private static void task1() {
try {
System.out.println("任务1执行开始");
Thread.sleep(5000);
System.out.println("任务1执行结束");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void task2() {
try {
System.out.println("任务2执行开始");
Thread.sleep(3000);
System.out.println("任务2执行结束");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
---------------------------
任务1执行开始
任务2执行开始
任务2执行结束
任务1执行结束
执行结果:-------------->task2Success--task1Success
执行时长------>5.041秒
thenRun无回调
如果我们不对异步执行结果进行加工处理,只是想知道该异步方法是否执行完成,则可以使用thenRun(Function<T,R>) 方法。这个方法只是一个异步完成的通知方法,告诉开发者,异步方法执行完成了。
public class Test1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long start = System.currentTimeMillis();
// 执行任务1
CompletableFuture<String> comFeature1 = CompletableFuture.supplyAsync(()->{
task1();
return "task1Success";
});
// 执行任务2
CompletableFuture.supplyAsync(()->{
task2();
return "task2Success";
}).thenRun(()->{
System.out.println("task2222回调了--------->");
}).join();
Long end = System.currentTimeMillis();
System.out.println("执行时长------>"+ (end - start) / 1000.0 +"秒");
}
private static void task1() {
try {
System.out.println("任务1执行开始");
Thread.sleep(5000);
System.out.println("任务1执行结束");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void task2() {
try {
System.out.println("任务2执行开始");
Thread.sleep(3000);
System.out.println("任务2执行结束");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
--------------------
任务1执行开始
任务2执行开始
任务2执行结束
task2222回调了--------->
执行时长------>3.047秒
两个任务的组合
/*
* 进行两个异步任务的编排调用-------这两个异步任务可存在依赖关系
* 例如 任务1 执行完成的结果 正是任务2的条件
* */
public class Test1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long start = System.currentTimeMillis();
// 执行任务1
CompletableFuture<String> comFeature1 = CompletableFuture.supplyAsync(() -> {
task1();
return "task1Success";
});
// 将任务1结果传给任务2
CompletableFuture<String> stringCompletableFuture = comFeature1.thenCompose(result -> CompletableFuture.supplyAsync(()->{
String str = result+"---"+"task1Success";
return str.trim();
}));
String join = stringCompletableFuture.join();
System.out.println("执行结果为:----------->" + join);
Long end = System.currentTimeMillis();
System.out.println("执行时长------>" + (end - start) / 1000.0 + "秒");
}
private static void task1() {
try {
System.out.println("任务1执行开始");
Thread.sleep(5000);
System.out.println("任务1执行结束");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
------------------------------
任务1执行开始
任务1执行结束
执行结果为:----------->task1Success---task1Success
执行时长------>5.034秒
总结
如果需要回调方法对结果进行处理,并且需要回调方法处理完成之后,返回具体处理结果。则使用thenApply(Function<T,R>)方法。
如果需要回调方法对结果进行处理,回调方法处理完成之后,不返回具体处理结果。则使用thenAeecpt(Function<T,R>) 方法。
如果不对结果进行处理,只是通知开发完成异步方法的调用了,则使用thenRun(Function<T,R>) 方法。
需要注意的是,这三个方法都支持 lamda 表达式和链式调用。