模拟线程池与异步方法调用查询接口优化
问题:批量查询如何优化?
entity实体类
package com.itheima.alipay.prop; import lombok.Data; @Data public class UserInfo { private Long userId; private String username; private int age; public UserInfo(Long userId, String username, int age) { this.userId = userId; this.username = username; this.age = age; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "UserInfo{" + "userId=" + userId + ", username='" + username + '\'' + ", age=" + age + '}'; } }
service模拟查询接口,设置睡眠时间模拟查询耗时
package com.itheima.alipay.prop; import lombok.SneakyThrows; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Service public class TestService { public static List<UserInfo> getUserInfo(List<Long> userIds) throws InterruptedException { long startTime = System.currentTimeMillis(); List<UserInfo> userInfos = new ArrayList<>(); // 模拟调用耗时 Thread.sleep(300); // 预定义的用户信息映射 final List<UserInfo> predefinedUsers = Arrays.asList( new UserInfo(1L, "李白", 20), new UserInfo(2L, "杜甫", 22), new UserInfo(3L, "白居易", 25), new UserInfo(4L, "王维", 27), new UserInfo(5L, "孟浩然", 29), new UserInfo(6L, "苏轼", 31), new UserInfo(7L, "辛弃疾", 33), new UserInfo(8L, "陆游", 35), new UserInfo(9L, "韩愈", 37), new UserInfo(0L, "柳宗元", 39) ); // 根据传入的userId查找用户信息 for (Long id : userIds) { for (UserInfo userInfo : predefinedUsers) { if (userInfo.getUserId().equals(id)) { // 模拟调用耗时 Thread.sleep(200); userInfos.add(userInfo); break; } } } // 计算并打印程序运行时间 long endTime = System.currentTimeMillis(); System.out.println(userInfos); return userInfos; } //public static List<UserInfo> getUserInfo(List<Long> userIds) throws InterruptedException { // long startTime = System.currentTimeMillis(); // // List<UserInfo> userInfos = new ArrayList<>(); // // // 预定义的用户信息映射 // final List<UserInfo> predefinedUsers = Arrays.asList( // new UserInfo(1L, "李白", 20), // new UserInfo(2L, "杜甫", 22), // new UserInfo(3L, "白居易", 25), // new UserInfo(4L, "王维", 27), // new UserInfo(5L, "孟浩然", 29), // new UserInfo(6L, "苏轼", 31), // new UserInfo(7L, "辛弃疾", 33), // new UserInfo(8L, "陆游", 35), // new UserInfo(9L, "韩愈", 37), // new UserInfo(0L, "柳宗元", 39) // ); // // // 使用Map来优化查找 // Map<Long, UserInfo> userMap = predefinedUsers.stream() // .collect(Collectors.toMap(UserInfo::getUserId, userInfo -> userInfo)); // // for (Long id : userIds) { // UserInfo userInfo = userMap.get(id); // if (userInfo != null) { // userInfos.add(userInfo); // } // } // // // 计算并打印程序运行时间 // long endTime = System.currentTimeMillis(); // System.out.println("获取用户信息耗时: " + (endTime - startTime) + "ms"); // System.out.println(userInfos); // // return userInfos; //} @Async("asyncPoolTaskExecutor") @SneakyThrows public List<UserInfo> fetchUserInfoAsync(List<Long> userIds) { long startTime = System.currentTimeMillis(); List<UserInfo> userInfos = getUserInfo(userIds); long endTime = System.currentTimeMillis(); System.out.println("异步调用耗时:" + (endTime - startTime) + "ms"); return userInfos; } }
controller层(便于方便异步方法线程池都写在了controller,实际开发根据需要调整)
package com.itheima.alipay.controller; import com.itheima.alipay.prop.Service; import com.itheima.alipay.prop.TestService; import com.itheima.alipay.prop.UserInfo; import com.itheima.alipay.prop.UserInfoResult; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PreDestroy; import javax.annotation.Resource; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.*; import java.util.stream.Collectors; @RestController public class db { @Resource private TestService testService; /** * 线程池异步查询,但结果采用了等待全部收集,阻塞相当于线程池并发执行 * 使用 CompletableFuture::join 方法同步等待所有任务完成,并合并结果。 * 整个方法是同步的,尽管任务是异步执行的,但方法本身会阻塞直到所有任务完成。 * @return */ @GetMapping("thread") public String qb() { long startTime = System.currentTimeMillis(); List<Long> userIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 0L); ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个固定大小的线程池 // 记录启动所有异步任务之前的时间 long startSubmitTime = System.currentTimeMillis(); List<CompletableFuture<List<UserInfo>>> futures = userIds.stream() .map(userId -> CompletableFuture.supplyAsync(() -> { try { return testService.getUserInfo(Collections.singletonList(userId)); // 查询单个userId的信息 } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CompletionException(e); } }, executor)) .collect(Collectors.toList()); // 打印启动所有异步任务之后的时间 long endSubmitTime = System.currentTimeMillis(); System.out.println("所有异步任务启动完成时间: " + (endSubmitTime - startSubmitTime) + "ms"); // 合并所有CompletableFuture的结果 List<UserInfo> allInfos = futures.stream() .map(CompletableFuture::join) .flatMap(List::stream) .collect(Collectors.toList()); // 输出结果 System.out.println(allInfos); long endTime = System.currentTimeMillis(); System.out.println("程序运行时间: " + (endTime - startTime) + "ms"); Long time = endTime - startTime; // 关闭线程池 executor.shutdown(); return allInfos + String.valueOf(time); } /** * 线程池异步查询,但结果采用了等待全部收集,阻塞相当于线程池并发执行 * 使用 CompletableFuture.allOf 方法异步等待所有任务完成。 * 使用 thenApply 方法异步构建最终的响应。 * 整个方法是异步的,不会阻塞主线程,适合处理高并发请求。 * @return */ @GetMapping("qb3") public CompletableFuture<ResponseEntity<UserInfoResult>> qb3() { long startTime = System.currentTimeMillis(); List<Long> userIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 0L); ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个固定大小的线程池 // 记录启动异步任务之前的时间 long startSubmitTime = System.currentTimeMillis(); List<CompletableFuture<List<UserInfo>>> futures = userIds.stream() .map(userId -> CompletableFuture.supplyAsync(() -> { try { return testService.getUserInfo(Collections.singletonList(userId)); } catch (Exception e) { e.printStackTrace(); throw new CompletionException(e); } }, executor)) // 将任务提交到线程池 .collect(Collectors.toList()); // 打印启动所有异步任务之后的时间 long endSubmitTime = System.currentTimeMillis(); System.out.println("所有异步任务启动完成时间: " + (endSubmitTime - startSubmitTime) + "ms"); // 合并所有CompletableFuture的结果 CompletableFuture<List<UserInfo>> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) .thenApply(v -> futures.stream() .map(CompletableFuture::join) .flatMap(List::stream) .collect(Collectors.toList())); // 构建最终的响应 CompletableFuture<ResponseEntity<UserInfoResult>> result = allFutures.thenApply(infos -> { long endTime = System.currentTimeMillis(); long duration = endTime - startTime; System.out.println("程序运行时间: " + duration + "ms"); // 将结果封装为UserInfoResult对象 UserInfoResult userInfoResult = new UserInfoResult(infos, duration); // 返回HTTP响应实体 return ResponseEntity.ok(userInfoResult); }).exceptionally(ex -> { ex.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new UserInfoResult(Collections.emptyList(), -1)); }); executor.shutdown(); return result; } /** * 同步方法执行 * @return */ @GetMapping("now") public String qb1() { try { long startTime = System.currentTimeMillis(); List<Long> userIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 0L); List<UserInfo> infos = testService.getUserInfo(userIds); long endTime = System.currentTimeMillis(); System.out.println("程序运行时间: " + (endTime - startTime) + "ms"); Long time = endTime - startTime; System.out.println(infos); return infos + String.valueOf(time); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // Restore interrupted status System.err.println("Thread was interrupted."); return "error"; } } /** * 调用异步任务,接口任务启动即结束,耗时短,适合无需立即查看响应结果的操作 * @return */ @GetMapping("qb4") public CompletableFuture<ResponseEntity<UserInfoResult>> qb4() { long startTime = System.currentTimeMillis(); List<Long> userIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 0L); // 记录启动异步任务之前的时间 long startSubmitTime = System.currentTimeMillis(); System.out.println("Starting to submit async tasks at: " + startSubmitTime); CompletableFuture<List<UserInfo>> futures = CompletableFuture.supplyAsync(() -> { try { List<UserInfo> infos = testService.fetchUserInfoAsync(userIds); System.out.println("Fetched user infos in async method: " + infos); return infos; } catch (Exception e) { e.printStackTrace(); throw new CompletionException(e); } }); // 打印启动异步任务之后的时间 long endSubmitTime = System.currentTimeMillis(); System.out.println("异步任务启动完成时间: " + (endSubmitTime - startSubmitTime) + "ms"); CompletableFuture<ResponseEntity<UserInfoResult>> result = futures.thenApply(infos -> { long endTime = System.currentTimeMillis(); long duration = endTime - startTime; System.out.println("程序运行时间: " + duration + "ms"); // 将结果封装为UserInfoResult对象 UserInfoResult userInfoResult = new UserInfoResult(infos, duration); System.out.println("UserInfoResult created: " + userInfoResult); // 返回HTTP响应实体 return ResponseEntity.ok(userInfoResult); }).exceptionally(ex -> { ex.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new UserInfoResult(Collections.emptyList(), -1)); }); return result; } }