主页 > 游戏开发  > 

CompletableFuture

CompletableFuture

CompletableFuture 是 Java 8 引入的一个用于异步编程的类,它是 Future 接口的增强版本。以下是主要特点和常用方法:

基础创建: // 创建一个完成的 Future CompletableFuture<String> cf1 = CompletableFuture pletedFuture("Hello"); // 创建一个异步执行的 Future CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> { return "Hello Async"; }); 转换和链式操作: CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World") // 转换值 .thenAccept(System.out::println) // 消费值 .thenRun(() -> System.out.println("Done")); // 执行操作 组合多个 Future: CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "Hello"); CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> "World"); // 组合两个 Future cf1.thenCombine(cf2, (result1, result2) -> result1 + " " + result2) .thenAccept(System.out::println); 异常处理: CompletableFuture.supplyAsync(() -> { throw new RuntimeException("出错了"); }) .exceptionally(throwable -> { System.out.println("发生错误:" + throwable.getMessage()); return "默认值"; }) .thenAccept(System.out::println); 实际应用示例: public class Service { public CompletableFuture<String> getDataAsync() { return CompletableFuture.supplyAsync(() -> { // 模拟耗时操作 try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return "数据"; }); } public void process() { getDataAsync() .thenApply(data -> data + "处理") .thenAccept(result -> System.out.println("结果: " + result)) .exceptionally(ex -> { System.err.println("处理失败: " + ex.getMessage()); return null; }); } }

主要方法说明:

supplyAsync(): 异步执行有返回值的任务runAsync(): 异步执行无返回值的任务thenApply(): 转换值(类似 map)thenAccept(): 消费值(无返回值)thenCombine(): 组合两个 FutureallOf(): 等待多个 Future 全部完成anyOf(): 等待多个 Future 中的任意一个完成

使用建议:

优先使用 thenCompose() 而不是 thenApply() 来组合返回 CompletableFuture 的方法记得处理异常,可以使用 exceptionally() 或 handle()如果需要自定义线程池,可以在创建时指定:CompletableFuture.supplyAsync(supplier, executor)

这些是 CompletableFuture 的基础用法,它能大大简化异步编程的复杂度。需要注意的是,CompletableFuture 默认使用 ForkJoinPool monPool(),在生产环境中可能需要考虑使用自定义的线程池。


项目场景

批量修改信息 1)请求类,接受图片 id 列表等字段:

@Data public class PictureEditByBatchRequest implements Serializable { /** * 图片 id 列表 */ private List<Long> pictureIdList; /** * 空间 id */ private Long spaceId; /** * 分类 */ private String category; /** * 标签 */ private List<String> tags; private static final long serialVersionUID = 1L; }

2)开发批量修改图片服务,依次完成参数校验、空间权限校验、图片查询、批量更新操作:

@Override @Transactional(rollbackFor = Exception.class) public void editPictureByBatch(PictureEditByBatchRequest pictureEditByBatchRequest, User loginUser) { List<Long> pictureIdList = pictureEditByBatchRequest.getPictureIdList(); Long spaceId = pictureEditByBatchRequest.getSpaceId(); String category = pictureEditByBatchRequest.getCategory(); List<String> tags = pictureEditByBatchRequest.getTags(); // 1. 校验参数 ThrowUtils.throwIf(spaceId == null || CollUtil.isEmpty(pictureIdList), ErrorCode.PARAMS_ERROR); ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR); // 2. 校验空间权限 Space space = spaceService.getById(spaceId); ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在"); if (!loginUser.getId().equals(space.getUserId())) { throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间访问权限"); } // 3. 查询指定图片,仅选择需要的字段 List<Picture> pictureList = this.lambdaQuery() .select(Picture::getId, Picture::getSpaceId) .eq(Picture::getSpaceId, spaceId) .in(Picture::getId, pictureIdList) .list(); if (pictureList.isEmpty()) { return; } // 4. 更新分类和标签 pictureList.forEach(picture -> { if (StrUtil.isNotBlank(category)) { picture.setCategory(category); } if (CollUtil.isNotEmpty(tags)) { picture.setTags(JSONUtil.toJsonStr(tags)); } }); // 5. 批量更新 boolean result = this.updateBatchById(pictureList); ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR); }

上述是调用mybatis plus 的 updateBatchById 批量更新的操作。如果要处理大量数据,可以使用线程池 + 分批 + 并发进行优化,参考代码如下:

@Resource private ThreadPoolExecutor customExecutor; /** * 批量编辑图片分类和标签 */ @Override @Transactional(rollbackFor = Exception.class) public void batchEditPictureMetadata(PictureBatchEditRequest request, Long spaceId, Long loginUserId) { // 参数校验 validateBatchEditRequest(request, spaceId, loginUserId); // 查询空间下的图片 List<Picture> pictureList = this.lambdaQuery() .eq(Picture::getSpaceId, spaceId) .in(Picture::getId, request.getPictureIds()) .list(); if (pictureList.isEmpty()) { throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "指定的图片不存在或不属于该空间"); } // 分批处理避免长事务 int batchSize = 100; List<CompletableFuture<Void>> futures = new ArrayList<>(); for (int i = 0; i < pictureList.size(); i += batchSize) { List<Picture> batch = pictureList.subList(i, Math.min(i + batchSize, pictureList.size())); // 异步处理每批数据 CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { batch.forEach(picture -> { // 编辑分类和标签 if (request.getCategory() != null) { picture.setCategory(request.getCategory()); } if (request.getTags() != null) { picture.setTags(String.join(",", request.getTags())); } }); boolean result = this.updateBatchById(batch); if (!result) { throw new BusinessException(ErrorCode.OPERATION_ERROR, "批量更新图片失败"); } }, customExecutor); futures.add(future); } // 等待所有任务完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); } 示例图如下

标签:

CompletableFuture由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“CompletableFuture