异步编程CompletableFuture

目录

为什么用CompletableFuture,异步编程还能用哪些类?

CompletableFuture怎么用?


为什么用CompletableFuture,异步编程还能用哪些类?

  • Future和Callable
// 创建一个固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);

// 创建多个 Callable 对象
List<Callable<String>> callableTasks = new ArrayList<>();
    callableTasks.add(() -> {
            Thread.sleep(2000); // 模拟耗时操作
            return "Task 1";
            });
            callableTasks.add(() -> {
            Thread.sleep(1000); // 模拟耗时操作
            return "Task 2";
            });
            callableTasks.add(() -> {
            Thread.sleep(1500); // 模拟耗时操作
            return "Task 3";
            });

    try {
        // 提交多个 Callable 任务并同时等待它们的完成
        List<Future<String>> futures = executor.invokeAll(callableTasks);
        // 提交单个 Callable 任务并获得 Future 对象
        //     创建一个 Callable 对象
        // Callable<String> callableTask = () -> {
        //    Thread.sleep(2000); // 模拟耗时操作
        //    return "Hello from Callable!";
        // };
        // Future<String> future = executor.submit(callableTask);

        // 处理每个任务的结果
        for (Future<String> future : futures) {
            String result = future.get();
            System.out.println(result);
        }
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

    // 关闭线程池
    executor.shutdown();

缺点:没有回调函数。不支持异常处理。

CompletableFuture怎么用?

CompletableFuture支持回调函数和异常处理,掌握下面14个方法。

  • runAsync(Runnable runnable):开启异步运行任务,并且不从任务中返回任何内容。它接受一个Runnable接口实现类对象,方法返回CompletableFuture<Void>对象
  • supplyAsync(Supplier<U> supplier):开启异步运行任务,会从任务中返回结果。它接收一个Supplier<U>供给者,用于供给带返回值的异步任务并返回CompletableFuture<U>
    • runAsync(Runnable runnable,Executor executor)和supplyAsync(Supplier<U> supplier,Executor executor):还可以接收自定义线程池。否则默认使用ForkJoinPool.commonPool() 线程池。如果所有completableFuture共享一个线程池,那么一旦有异步任务执行一些很慢的I/O操作,就会导致线程池中所有的线程都阻塞在I/O操作上,从而造成线程饥饿,进而影响整个系统的性能。
  • thenApply(Function<? super T,? extends U> fn):异步任务的回调函数,会返回一个新的结果
  • thenAccept(Consumer<T>)异步任务的回调函数,不返回结果
  • thenRun(Runnable action):异步任务的回调函数,得到一个完成的通知,甚至都不使用上一个链式操作的结果
    • 异步回调
    • CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) 
      // 回调方的异步变体(异步回调)
      CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
      CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) 
      // thenAccept和其异步回调
      CompletableFuture<Void> thenAccept(Consumer<? super T> action)
      CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
      CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action Executor executor)
      // thenRun和其异步回调
      CompletableFuture<Void> thenRun(Runnable action)
      CompletableFuture<Void> thenRunAsync(Runnable action)
      CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
  • thenCompose(Function<? super T, ? extends CompletionStage<U>> fn):组合两个有依赖关系的异步任务,结果由第二个任务返回
  •  thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn):组合两个没有依赖关系的异步任务
  • allOf(CompletableFuture<?>... cfs):组合多个异步任务,当所有异步任务都完成时可以进一步操作
  • anyOf(CompletableFuture<?>... cfs):组合多个异步任务,当任何一个异步任务完成时就可以进一步操作
  • exceptionally(Function<Throwable,? extends T> fn): 用于处理多个连续回调函数上的异常, 回调链上出现的任何异常,回调链不继续向下执行,都在exceptionally中处理异常。
  • handle(BiFunction<? super T, Throwable, ? extends U> fn):常被用来恢复多个连续回调函数上的异常,回调链恢复后可继续向下执行
  • applyToEither() 把两个异步任务做比较,异步任务先到结果的,就对先到的结果进行下一步操作。
  • acceptEither() 把两个异步任务做比较,异步任务先到结果的,就对先到的结果进行下一步操作(消费使用)。
  • runAfterEither() :如果不关心最先到达的结果,只想在有一个异步任务完成时得到完成的通知,可以使用

案例:

// 异步处理多个文件
public boolean uploadSfzImg(String yhdm, MultipartFile[] fileArr){
    // 创建文件夹
    String path = this.getClass().getResource("/").getPath() + File.separator + Constant.FILE_TEMP_PATH+File.separator+ yhdm;
    File tempFile = new File(path);
    if(!tempFile.exists()){
        tempFile.mkdirs();
    }
    final ExecutorService executorService = Executors.newFixedThreadPool(fileArr.length);
    // 每一个文件开启一个异步任务
    List<CompletableFuture<Boolean>> fileFutureList = Arrays.stream(fileArr).map(file -> {
        CompletableFuture<Boolean> fileFuture = CompletableFuture.supplyAsync(() -> {
            try {
                file.transferTo(new File(Constant.FILE_TEMP_PATH + File.separator + file.getOriginalFilename()));
            } catch (IOException e) {
                log.error("上传图片失败:"+file.getOriginalFilename()+ e.getMessage(), e);
                return false;
            }
            return true;
        },executorService);
        return fileFuture;
    }).collect(Collectors.toList());

    CompletableFuture[] fileFutureArr = fileFutureList.toArray(new CompletableFuture[fileFutureList.size()]);

    // 将多个异步任务合并
    CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(fileFutureArr);
    // 异步任务的回调函数,统计成功的个数
    CompletableFuture<Long> count = allOfFuture.thenApply(v -> {
        return fileFutureList.stream().map(b -> {
            return b.join();
        }).filter(b -> b).count();
    });
    // 关闭线程池
    executorService.shutdown();
    // 都成功
    if(count.join() == fileArr.length){
        // todo 批量入库,返回成功
        return true;
    }else {
        // 删除全部上传的文件,返回失败
        for (MultipartFile file : fileArr) {
            String originalFilename = file.getOriginalFilename();
            new File(tempFile + File.separator +Constant.FILE_TEMP_PATH + File.separator + originalFilename).delete();
        }
        return false;
    }
}

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值