面试题答案
一键面试设计思路
- 任务编排:使用
CompletableFuture
来编排多线程异步任务,利用其链式调用和组合方法,如thenApply
、thenCompose
等,按顺序执行任务。 - 错误处理:通过
exceptionally
方法捕获异步任务中的异常,并进行错误恢复处理。根据不同的异常类型进行针对性处理。 - 数据库事务一致性:在数据库操作时,利用数据库事务管理机制,如 Spring 的
@Transactional
注解(假设使用 Spring 框架)。如果异步任务中数据库操作失败,回滚事务以保证一致性。 - 外部服务资源释放:为外部服务调用编写资源释放逻辑,确保在出现异常时能正确释放资源。可以使用
try - finally
块或者 Java 7 引入的try - with - resources
语法。
关键代码片段
假设使用 Java 8 和 Spring 框架,以下是示例代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Service
public class TaskService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private ExternalService externalService;
@Transactional
public CompletableFuture<String> executeTasks() {
return CompletableFuture.supplyAsync(() -> {
// 模拟异步任务 1
if (Math.random() > 0.5) {
throw new RuntimeException("Async Task 1 failed");
}
return "Task 1 completed";
})
.thenApply(result1 -> {
// 模拟异步任务 2,依赖任务 1 的结果
if (Math.random() > 0.5) {
throw new RuntimeException("Async Task 2 failed");
}
return result1 + ", Task 2 completed";
})
.thenCompose(result2 -> {
// 调用外部服务
return CompletableFuture.supplyAsync(() -> {
try {
return externalService.callExternalService(result2);
} catch (Exception e) {
throw new RuntimeException("External service call failed", e);
}
});
})
.thenApply(result3 -> {
// 数据库操作
jdbcTemplate.update("INSERT INTO tasks (result) VALUES (?)", result3);
return result3 + ", Database operation completed";
})
.exceptionally(ex -> {
// 错误恢复处理
if (ex instanceof RuntimeException) {
if (ex.getMessage().contains("Async Task 1 failed")) {
// 针对任务 1 失败的恢复逻辑
System.out.println("Recovering from Async Task 1 failure");
} else if (ex.getMessage().contains("Async Task 2 failed")) {
// 针对任务 2 失败的恢复逻辑
System.out.println("Recovering from Async Task 2 failure");
} else if (ex.getMessage().contains("External service call failed")) {
// 针对外部服务调用失败的恢复逻辑
externalService.releaseResources();
System.out.println("Recovering from external service call failure");
} else {
// 通用恢复逻辑
System.out.println("General recovery from failure");
}
}
return "Task failed: " + ex.getMessage();
});
}
}
class ExternalService {
public String callExternalService(String input) throws Exception {
// 模拟外部服务调用
if (Math.random() > 0.5) {
throw new Exception("External service error");
}
return input + ", External service call completed";
}
public void releaseResources() {
// 释放外部服务资源逻辑
System.out.println("External service resources released");
}
}
不同错误类型下的针对性处理
- 异步任务自身错误:在
exceptionally
块中,通过判断异常信息中是否包含特定任务失败的标识,进行针对性恢复处理。如if (ex.getMessage().contains("Async Task 1 failed"))
。 - 外部服务调用错误:捕获外部服务调用时抛出的异常,在
exceptionally
块中调用externalService.releaseResources()
释放资源,并进行相应恢复逻辑。 - 数据库操作错误:由于使用了
@Transactional
注解,数据库操作失败时会自动回滚事务,保证一致性。exceptionally
块中可以记录错误日志等通用恢复操作。