面试题答案
一键面试获取结果方式的不同
- Future接口:
- get()方法:通过调用
Future
的get()
方法来获取异步任务的结果。此方法是阻塞的,即调用线程会一直等待,直到异步任务完成并返回结果。如果异步任务抛出异常,get()
方法会将异常重新抛出。例如:
ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(() -> { // 模拟耗时操作 Thread.sleep(2000); return 42; }); try { Integer result = future.get(); System.out.println("Result: " + result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executor.shutdown(); }
- get(long timeout, TimeUnit unit)方法:该方法同样用于获取结果,但设置了超时时间。如果在指定的超时时间内任务未完成,会抛出
TimeoutException
。
- get()方法:通过调用
- CompletableFuture:
- thenApply()系列方法:
CompletableFuture
提供了一系列非阻塞的方法来处理异步任务的结果。例如thenApply()
,它接收一个函数作为参数,当CompletableFuture
完成时,会将结果作为参数传递给这个函数,并返回一个新的CompletableFuture
包含处理后的结果。例如:
CompletableFuture.supplyAsync(() -> { // 模拟耗时操作 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return 42; }).thenApply(result -> "Result is: " + result).thenAccept(System.out::println);
- join()和get()方法:
CompletableFuture
也有get()
方法,和Future
接口的get()
方法类似,是阻塞的。join()
方法和get()
方法功能类似,但join()
方法不会抛出受检异常,而是将异常包装成CompletionException
。
- thenApply()系列方法:
应用场景及选择
- Future接口适用场景:
- 简单阻塞获取结果场景:当你的应用程序逻辑比较简单,只需要等待异步任务完成并获取结果,并且不关心异步任务完成后如何进一步处理结果,
Future
接口是一个简单直接的选择。例如,在一些工具类方法中,异步执行一个计算任务,然后获取结果进行后续的简单操作。
- 简单阻塞获取结果场景:当你的应用程序逻辑比较简单,只需要等待异步任务完成并获取结果,并且不关心异步任务完成后如何进一步处理结果,
- CompletableFuture适用场景:
- 复杂异步任务链场景:当你需要将多个异步任务链接起来,例如一个任务的输出作为另一个任务的输入,并且希望以非阻塞的方式处理这些任务时,
CompletableFuture
更合适。例如在微服务架构中,可能需要依次调用多个服务,每个服务的调用都是异步的,并且后一个服务依赖前一个服务的结果。 - 异步任务组合场景:
CompletableFuture
提供了诸如allOf()
和anyOf()
等方法,可以方便地组合多个异步任务。例如,你需要等待多个异步任务全部完成或者只要有一个任务完成就进行下一步操作,这种情况下CompletableFuture
能提供更好的编程体验和性能优化。例如,同时发起多个HTTP请求获取数据,然后将这些数据汇总处理,就可以使用CompletableFuture.allOf()
来等待所有请求完成。
- 复杂异步任务链场景:当你需要将多个异步任务链接起来,例如一个任务的输出作为另一个任务的输入,并且希望以非阻塞的方式处理这些任务时,