异步编排
在业务开发的过程中,我们为了降低接口耗时,经常会用到线程池,书写多线程数据获取、同步阻塞获取结果的业务逻辑。
常见的使用方法如下:
Future
@Slf4j
@SpringBootTest
public class OtherTest {
public static final ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
public static void main(String[] args) {
Future<Integer> submit1 = executor.submit(() -> {
// 业务耗时逻辑1
return 1;
});
Future<Integer> submit2 = executor.submit(() -> {
// 业务耗时逻辑2
return 2;
});
Future<Integer> submit3 = executor.submit(() -> {
// 业务耗时逻辑3
return 3;
});
try {
Integer integer1 = submit1.get();
Integer integer2 = submit2.get();
Integer integer3 = submit3.get();
System.out.println(integer1);
System.out.println(integer2);
System.out.println(integer3);
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
假设一个接口涉及到3个业务逻辑,如下:
- 业务逻辑1耗时: 50ms
- 业务逻辑2耗时: 30ms
- 业务逻辑3耗时: 70ms
那么如果是传统的串行调用,接口总耗时:150ms
但如果是上面的利用线程池的方式进行调用,那么该接口耗时取决于耗时最长的那个业务逻辑,即该接口耗时为: 70ms
可以看到,接口耗时是有明显降低的~
CompletableFuture
当然,上面虽然对接口进行异步编排后,接口耗时有着下降,但是如果说我们的耗时业务逻辑有着十几二十个?且业务逻辑之间存在依赖关系?那么我们怎么办?
很显然,上面的Future
就不能满足我们的需求了,所以从JDK8开始,JDK提供了CompletableFuture
工具类,为我们异步编排提供了很大的便利~
@Slf4j
@SpringBootTest
public class OtherTest {
public static final ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
public static void main(String[] args) {
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
// 业务耗时逻辑1
return 1;
}, executor);
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
// 业务耗时逻辑2
return 2;
}, executor);
CompletableFuture<