面试题答案
一键面试功能差异
thenApply
:接收一个Function
作为参数,该Function
会对CompletableFuture
的结果进行处理并返回一个新的结果,生成一个新的CompletableFuture
。例如:
CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(s -> s + ", World")
.thenAccept(System.out::println);
thenAccept
:接收一个Consumer
作为参数,该Consumer
会对CompletableFuture
的结果进行处理,但不返回新的结果,返回的CompletableFuture
的结果为Void
。例如:
CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(System.out::println);
thenRun
:接收一个Runnable
作为参数,不关心CompletableFuture
的结果,只是在CompletableFuture
完成时执行该Runnable
任务,返回的CompletableFuture
的结果为Void
。例如:
CompletableFuture.supplyAsync(() -> "Hello")
.thenRun(() -> System.out.println("Task completed"));
适用场景差异
thenApply
:适用于需要对异步操作的结果进行转换,生成新的结果供后续异步操作使用的场景。比如从数据库查询数据后,对数据进行格式转换再返回给调用方。thenAccept
:适用于只需要对异步操作的结果进行处理,而不需要返回新结果的场景。例如,将查询到的数据写入日志文件。thenRun
:适用于不依赖异步操作结果,只在异步操作完成时执行一些额外任务的场景。例如,记录异步任务完成的时间戳。
性能差异
在性能方面,它们本身并没有显著差异,主要性能消耗在于任务本身的执行时间。然而,thenRun
相对更轻量级,因为它不关心前序任务的结果,thenAccept
次之,thenApply
需要处理并返回新结果,可能相对复杂一点,但这种差异在大多数情况下可以忽略不计。
高并发且对响应时间敏感系统的优化方案
- 减少不必要的转换:在高并发且响应时间敏感的系统中,尽量避免使用
thenApply
进行无意义的结果转换。如果只是对结果进行处理,优先使用thenAccept
。 - 并行处理:使用
CompletableFuture
的thenApplyAsync
、thenAcceptAsync
、thenRunAsync
等方法,将任务提交到线程池中并行执行,充分利用多核CPU的优势。 - 减少阻塞:确保异步任务内部不进行长时间的阻塞操作,如同步I/O等。如果无法避免,考虑使用异步I/O。
代码示例
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureOptimization {
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture.supplyAsync(() -> calculateResult(), executor)
.thenApplyAsync(CompletableFutureOptimization::processResult, executor)
.thenAcceptAsync(System.out::println, executor);
executor.shutdown();
}
private static int calculateResult() {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
}
private static String processResult(int result) {
// 模拟结果处理
return "The result is: " + result;
}
}
在上述示例中,calculateResult
方法模拟一个耗时操作,processResult
方法模拟对结果的处理。通过thenApplyAsync
和thenAcceptAsync
方法将任务提交到线程池中并行执行,从而提高系统在高并发场景下的性能。