业务背景
- 返回给前端的VO类是需要调用三种不同的
Service方法或Feign来拼接而成的。 - 由于系统需要同时访问多个数据源,传统的同步调用会导致多个 API 调用的串行执行,这显著影响了响应时间和系统吞吐量。
解决
- 通过
CompletableFuture来实现异步调用。
大致代码如下:
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class AsyncExample {
private static Executor executor = Executors.newFixedThreadPool(10); // 自定义线程池
public static void main(String[] args) {
// 示例输入数据
List<String> employeeIds = Arrays.asList("emp1", "emp2", "emp3");
List<String> customerIds = Arrays.asList("cus1", "cus2");
List<String> chatIds = Arrays.asList("chat1", "chat2");
// 执行异步任务
fetchUserData(employeeIds, customerIds, chatIds);
}
public static void fetchUserData(List<String> employeeIds, List<String> customerIds, List<String> chatIds) {
// 异步获取员工、客户和群聊信息
CompletableFuture<Map<String, Employee>> employeeFuture = fetchEmployeeInfo(employeeIds);
CompletableFuture<Map<String, Customer>> customerFuture = fetchCustomerInfo(customerIds);
CompletableFuture<Map<String, ChatGroup>> chatFuture = fetchChatGroupInfo(chatIds);
// 等待所有异步任务完成
CompletableFuture<Void> allOf = CompletableFuture.allOf(employeeFuture, customerFuture, chatFuture);
// 在所有任务完成后进行结果处理
allOf.thenRun(() -> {
Map<String, Employee> employees = employeeFuture.join();
Map<String, Customer> customers = customerFuture.join();
Map<String, ChatGroup> chats = chatFuture.join();
// 处理获取的结果
processResults(employees, customers, chats);
}).join(); // 阻塞当前线程直到异步操作完成
}
// 获取员工信息的异步任务
private static CompletableFuture<Map<String, Employee>> fetchEmployeeInfo(List<String> employeeIds) {
return CompletableFuture.supplyAsync(() -> {
// 模拟从外部系统或数据库获取员工信息
return employeeIds.stream()
.collect(Collectors.toMap(Function.identity(), id -> new Employee(id, "Employee " + id)));
}, executor);
}
// 获取客户信息的异步任务
private static CompletableFuture<Map<String, Customer>> fetchCustomerInfo(List<String> customerIds) {
return CompletableFuture.supplyAsync(() -> {
// 模拟从外部系统或数据库获取客户信息
return customerIds.stream()
.collect(Collectors.toMap(Function.identity(), id -> new Customer(id, "Customer " + id)));
}, executor);
}
// 获取群聊信息的异步任务
private static CompletableFuture<Map<String, ChatGroup>> fetchChatGroupInfo(List<String> chatIds) {
return CompletableFuture.supplyAsync(() -> {
// 模拟从外部系统或数据库获取群聊信息
return chatIds.stream()
.collect(Collectors.toMap(Function.identity(), id -> new ChatGroup(id, "Chat Group " + id)));
}, executor);
}
// 处理获取到的所有结果
private static void processResults(Map<String, Employee> employees, Map<String, Customer> customers, Map<String, ChatGroup> chats) {
// 示例:输出所有获取到的信息
System.out.println("Employees: " + employees);
System.out.println("Customers: " + customers);
System.out.println("Chats: " + chats);
}
// 示例数据对象
static class Employee {
String id;
String name;
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Employee{id='" + id + "', name='" + name + "'}";
}
}
static class Customer {
String id;
String name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Customer{id='" + id + "', name='" + name + "'}";
}
}
static class ChatGroup {
String id;
String name;
public ChatGroup(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "ChatGroup{id='" + id + "', name='" + name + "'}";
}
}
}
异步回调要传线程池?
建议强制传线程池,且根据实际情况做线程池隔离。
当不传递线程池时,会使用ForkJoinPool中的公共线程池CommonPool,这里所有调用将共用该线程池,核心线程数=处理器数量-1(单核核心线程数为1),所有异步回调都会共用该CommonPool,核心与非核心业务都竞争同一个池中的线程,很容易成为系统瓶颈。手动传递线程池参数可以更方便的调节参数,并且可以给不同的业务分配不同的线程池,以求资源隔离,减少不同业务之间的相互干扰。
来自:美团技术团队