一、前言:异步编程中的痛点
在现代Java应用中,异步编程已成为提升系统性能的必备技能。Future接口让我们能够以非阻塞的方式处理耗时操作,但在实际使用中,容易遇到了几个棘手的痛点:
- 异常处理代码重复:每次调用
future.get()都需要完整的try-catch块,代码冗余且难以维护 - 降级策略不统一:对于同一个异步结果,不同业务场景需要不同的降级策略
- 超时配置分散:同一异步操作在不同上下文中需要不同的超时设置
- 语义化不足:
Future本身只是一个"占位符",缺乏业务语义的表达能力
今天将介绍一个简洁而强大的工具类FutureValueHolder,它可以让异步编程变得更加优雅。
二、核心解析:双重检查锁的精妙设计
2.1 核心数据结构
public class FutureValueHolder<T> {
private final Future<T> future;
private final Long timeout;
private final TimeUnit unit;
private boolean invoked = false;
private T value = null;
}
- future: 包装的原始异步任务
- timeout/unit: 超时控制参数
- invoked: 标记是否已执行获取操作
- value: 缓存的结果值
2.2 工厂方法模式
public static <T> FutureValueHolder<T> of(Future<T> future, Long timeout, TimeUnit unit) {
return new FutureValueHolder<T>(future, timeout, unit);
}
使用静态工厂方法创建实例,提供更好的类型推断和API设计。
2.3 核心算法:双重检查锁
public T get() {
if (invoked) { // 第一次检查(无锁)
return value;
}
synchronized (this) { // 加锁
if (invoked) { // 第二次检查(有锁)
return value;
}
// 实际获取逻辑
value = future.get(timeout, unit);
invoked = true;
}
return value;
}
双重检查锁的优势:
- 性能优化:大多数情况无需加锁
- 线程安全:确保多线程环境下正确执行
- 单次执行:
future.get()只成功调用一次
2.4 两种获取策略
严格模式(get)
public T get() {
// ... 双重检查锁逻辑
try {
value = future.get(timeout, unit);
} catch (Exception e) {
throw new FutureValueHolderGetException(e); // 抛出异常
}
invoked = true;
}
安全模式(safeGet)
非关键业务,允许降级处理
public T safeGet() {
// ... 双重检查锁逻辑
try {
value = future.get(timeout, unit);
} catch (Exception e) {
// ...
}
invoked = true;
}
三、应用示范:真实场景下的威力
3.1 场景一:用户信息服务
public class UserService {
public UserDetailDTO getUserDetail(Long userId) {
FutureValueHolder<User> userHolder = FutureValueHolder.of(
userDao.getUserAsync(userId), 3L, TimeUnit.SECONDS);
FutureValueHolder<List<Order>> ordersHolder = FutureValueHolder.of(
orderDao.getOrdersAsync(userId), 3L, TimeUnit.SECONDS);
// 第一次获取(可能等待)
User user = userHolder.get();
List<Order> orders = ordersHolder.get();
// 后续访问(零等待)
String name = userHolder.get().getName(); // 立即返回
Integer age = userHolder.get().getAge(); // 立即返回
String email = userHolder.get().getEmail(); // 立即返回
return buildDTO(userHolder.get(), ordersHolder.get());
}
}
3.2 场景二:外部API调用降级
传统写法(冗长的异常处理)
public class WeatherService {
public WeatherInfo getWeather(String city) {
Future<WeatherInfo> future = weatherApi.getAsync(city);
try {
return future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
log.error("天气API超时", e);
return WeatherInfo.defaultInfo();
} catch (ExecutionException e) {
log.error("天气API执行异常", e);
return WeatherInfo.defaultInfo();
} catch (InterruptedException e) {
log.error("天气API被中断", e);
return WeatherInfo.defaultInfo();
}
}
}
使用FutureValueHolder(简洁优雅)
public class WeatherService {
public WeatherInfo getWeather(String city) {
FutureValueHolder<WeatherInfo> holder = FutureValueHolder.of(
weatherApi.getAsync(city), 5L, TimeUnit.SECONDS);
// 简洁明了
WeatherInfo info = holder.safeGet();
return info != null ? info : WeatherInfo.defaultInfo();
}
}
四、完整代码
public class FutureValueHolder<T> {
private final Future<T> future;
private final Long timeout;
private final TimeUnit unit;
private boolean invoked = false;
private T value = null;
private FutureValueHolder(Future<T> future, Long timeout, TimeUnit unit) {
this.future = future;
this.timeout = timeout;
this.unit = unit;
}
public static <T> FutureValueHolder<T> of(Future<T> future, Long timeout, TimeUnit unit) {
return new FutureValueHolder<T>(future, timeout, unit);
}
public T get() {
if (invoked) {
return value;
}
synchronized (this) {
if (invoked) {
return value;
}
try {
value = future.get(timeout, unit);
} catch (Exception e) {
throw new FutureValueHolderException(e);
}
invoked = true;
}
return value;
}
public T safeGet() {
if (invoked) {
return value;
}
synchronized (this) {
if (invoked) {
return value;
}
try {
value = future.get(timeout, unit);
} catch (Exception e) {
// ...
}
invoked = true;
}
return value;
}
}