一、应用场景
在实际的开发工作中,我们可能会遇到一些比较复杂且耗时的功能,例如一个业务数据表格的导出,假定业务数据表本身都很大,需要组装的数据又比较多,就会造成整个实现过程很耗时甚至可能出现接口请求超时;这个时候我们会想到把过程中耗时的查询和数据处理通过异步的方式来提升执行效率,但一些查询数据的组装需要等待结果再进行下一步处理,这个时候就要用到Java8引入的新特性:CompletableFuture
二、使用方法
假设现在有个接口,其中有3个比较耗时的查询:getSomething1()、getSomething2()、getSomething3();同步执行所需的时间即3个查询所需时间之和;使用CompletableFuture实现异步执行,等待所有查询结果,所需时间则为3个查询中最大的时间, 如下的示例中,3个查询共需要6秒,使用CompletableFuture优化后仅需3秒!
特别提醒:在使用CompletableFuture启动线程去执行任务后,切忌立马下一行调用get()方法,这样会阻塞线程,会导致多个CompletableFuture任务之间挨个等待,又变回同步执行了!
java
import cn.hutool.core.date.DateUtil;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("同步执行任务开始时间:" + DateUtil.now());
String something1 = getSomething1();
String something2 = getSomething2();
String something3 = getSomething3();
System.out.println("getSomething1() : " + something1);
System.out.println("getSomething2() : " + something2);
System.out.println("getSomething3() : " + something3);
System.out.println("同步执行任务结束时间:" + DateUtil.now());
System.out.println();
System.out.println("异步执行任务开始时间:" + DateUtil.now());
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(CompletableFutureTest::getSomething1);
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(CompletableFutureTest::getSomething2);
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(CompletableFutureTest::getSomething3);
System.out.println("getSomething1() : " + cf1.get());
System.out.println("getSomething2() : " + cf2.get());
System.out.println("getSomething3() : " + cf3.get());
System.out.println("异步执行任务结束时间:" + DateUtil.now());
}
public static String getSomething1() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "getSomething1";
}
public static String getSomething2() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "getSomething2";
}
public static String getSomething3() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "getSomething3";
}
}
控制台执行结果:
在实际开发中使用,推荐使用线程池去执行异步任务,supplyAsync()重载的方法中有支持线程池对象参数,快去体验吧!