MST

星途 面试题库

面试题:Java中CompletableFuture与Future在获取结果方式上的区别

请详细阐述Java中CompletableFuture和Future在获取异步任务执行结果方式上有哪些不同,并举例说明。
47.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 获取结果方式的不同

  • Future
    • Future获取异步任务执行结果主要通过get()方法。这个方法是阻塞的,即调用线程会一直等待,直到异步任务完成并返回结果。如果异步任务抛出异常,get()方法会将异常重新抛出。另外,Future还有get(long timeout, TimeUnit unit)方法,允许设置等待的超时时间,若超时任务仍未完成,会抛出TimeoutException
    • 它缺乏对异步任务完成后的链式处理能力,通常需要手动轮询isDone()方法来判断任务是否完成,以避免长时间阻塞。
  • CompletableFuture
    • CompletableFuture获取结果除了get()get(long timeout, TimeUnit unit)(与Future类似的阻塞方法)外,还提供了丰富的非阻塞方式。
    • 可以通过thenApplythenAcceptthenRun等方法在异步任务完成后进行链式处理。thenApply用于将前一个异步任务的结果作为参数,进行转换并返回新的结果;thenAccept用于消费前一个异步任务的结果,但不返回新结果;thenRun则在异步任务完成后执行一段无参的代码块。
    • CompletableFuture还支持多个异步任务的组合操作,如allOf(等待所有任务完成)和anyOf(只要有一个任务完成)。

2. 示例说明

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;
        });
        try {
            System.out.println("等待任务完成...");
            Integer result = future.get(); // 阻塞等待任务完成
            System.out.println("任务结果: " + result);
        } catch (TimeoutException e) {
            System.out.println("任务执行超时");
        } finally {
            executorService.shutdown();
        }
    }
}

CompletableFuture示例

import java.util.concurrent.*;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> {
            // 模拟耗时操作
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 42;
        }).thenApply(result -> {
            System.out.println("接收到结果: " + result);
            return result * 2;
        }).thenAccept(finalResult -> {
            System.out.println("最终结果: " + finalResult);
        });

        // 主线程防止退出
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Future示例中,get()方法阻塞主线程直到任务完成。而在CompletableFuture示例中,通过链式调用的方式,在任务完成后可以非阻塞地对结果进行处理,增强了异步编程的灵活性和可读性。