面试题答案
一键面试策略思路
- 单个任务异常处理:使用
exceptionally
方法捕获每个CompletableFuture
任务中的异常,以便在任务失败时进行相应处理。 - 依赖关系处理:确保异常处理逻辑不会破坏任务之间的依赖关系。如果某个任务失败,后续依赖它的任务应根据失败情况进行相应调整。
- 恢复机制:对于间歇性失败的任务,可以引入重试机制。例如,使用
CompletableFuture
的whenComplete
方法结合重试逻辑,在任务失败时进行重试。 - 性能与可维护性:为了保证性能,重试次数应有限制,避免无限循环。同时,将重试逻辑封装成独立的方法,提高代码的可维护性。
关键代码片段
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureErrorHandling {
// 重试次数限制
private static final int MAX_RETRIES = 3;
// 执行异步任务,带重试机制
private static CompletableFuture<String> performTaskWithRetry(int taskNumber) {
return performTask(taskNumber)
.whenComplete((result, ex) -> {
if (ex != null && taskNumber < MAX_RETRIES) {
performTaskWithRetry(taskNumber + 1)
.whenComplete((r, e) -> {
if (e != null && taskNumber == MAX_RETRIES - 1) {
System.err.println("Task failed after max retries: " + taskNumber);
}
});
}
});
}
// 模拟异步任务
private static CompletableFuture<String> performTask(int taskNumber) {
return CompletableFuture.supplyAsync(() -> {
// 模拟资源竞争导致的间歇性失败
if (Math.random() < 0.5) {
throw new RuntimeException("Task " + taskNumber + " failed due to resource competition");
}
return "Task " + taskNumber + " completed successfully";
});
}
public static void main(String[] args) {
CompletableFuture<Void> chain = performTaskWithRetry(1)
.thenApply(result -> {
System.out.println(result);
return result;
})
.thenCompose(result -> performTaskWithRetry(2))
.thenApply(result -> {
System.out.println(result);
return result;
})
.thenCompose(result -> performTaskWithRetry(3))
.thenApply(result -> {
System.out.println(result);
return result;
})
.exceptionally(ex -> {
System.err.println("Final chain failed: " + ex.getMessage());
return null;
})
.thenRun(() -> System.out.println("Chain completed"));
try {
chain.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
在上述代码中:
performTask
方法模拟了一个可能会间歇性失败的异步任务。performTaskWithRetry
方法实现了重试机制,在任务失败时会根据重试次数进行重试。main
方法展示了如何通过CompletableFuture
的链式调用构建依赖关系,并在其中应用错误处理和恢复策略。exceptionally
方法用于捕获整个链式调用中的最终异常,确保即使有任务失败,程序也能有相应的处理并继续执行后续逻辑。