MST
星途 面试题库

面试题:Java异步任务管理中Future和CompletableFuture的区别与使用场景

在Java异步任务管理方面,Future和CompletableFuture都有哪些特性?它们之间的主要区别是什么?请举例说明在不同的应用场景下,应该如何选择使用Future还是CompletableFuture。
38.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

Future特性

  1. 异步结果获取:可通过get()方法获取异步任务的执行结果,若任务未完成,get()方法会阻塞当前线程,直到任务完成。
  2. 任务取消:提供cancel(boolean mayInterruptIfRunning)方法来取消任务。若mayInterruptIfRunningtrue,正在执行的任务会被中断;若为false,则仅在任务未开始时能取消。
  3. 判断任务状态:可通过isDone()判断任务是否完成,通过isCancelled()判断任务是否被取消。

CompletableFuture特性

  1. 异步操作链:支持链式调用,能方便地将多个异步任务串联起来,例如thenApplythenAcceptthenRun等方法,无需像Future那样手动处理每个任务的结果获取与后续任务启动。
  2. 异步任务组合:可以将多个异步任务组合起来,如allOf方法等待所有任务完成,anyOf方法只要有一个任务完成就返回。
  3. 回调处理:提供了丰富的回调方法,当任务完成时可以执行相应的回调,如whenComplete方法可在任务完成时得到任务结果或异常。

主要区别

  1. 编程模型Future基于阻塞获取结果的模型,在获取结果时可能会阻塞线程。CompletableFuture基于异步回调和链式调用,无需阻塞线程,更符合现代异步编程风格。
  2. 功能丰富度CompletableFuture功能更丰富,支持异步任务的组合、链式调用以及多种回调处理方式,而Future相对功能较为单一。

应用场景选择

  1. 简单异步任务且需要获取结果:如果只是简单的异步任务,并且需要在主线程等待任务执行完毕获取结果,Future就可以满足需求。例如,在一个工具类中执行一个简单的异步计算任务,主线程需要获取计算结果继续后续操作。
import java.util.concurrent.*;

public class FutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<Integer> future = executorService.submit(() -> {
            // 模拟异步任务
            Thread.sleep(2000);
            return 42;
        });
        System.out.println("等待任务执行完毕...");
        Integer result = future.get();
        System.out.println("任务结果: " + result);
        executorService.shutdown();
    }
}
  1. 复杂异步任务组合与链式操作:当涉及到多个异步任务的组合、链式调用以及需要灵活的回调处理时,应选择CompletableFuture。比如,在一个电商系统中,需要先查询商品库存,根据库存结果决定是否进行下单操作,并且在操作完成后记录日志。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(() -> {
            // 查询商品库存
            System.out.println("查询商品库存...");
            return 10;
        })
        .thenApplyAsync(stock -> {
            if (stock > 0) {
                System.out.println("库存充足,进行下单操作...");
                return "订单已创建";
            } else {
                System.out.println("库存不足,无法下单");
                return "下单失败";
            }
        })
        .thenAcceptAsync(result -> System.out.println("操作结果: " + result))
        .thenRunAsync(() -> System.out.println("记录操作日志..."));

        // 主线程等待所有异步任务完成
        Thread.sleep(3000);
    }
}