OneShotLatch 是基于 AQS 独占模式实现的轻量级“一键阻塞”Future 替代品,state 仅允许 0→1 原子变更,支持中断、超时、JMM 安全的结果发布,并可通过 Spring Boot @Bean 注入。

直接基于 AQS 实现一个“一键阻塞”的 Future 替代品,核心不是造轮子,而是精准控制状态流转与线程唤醒时机。它比 CompletableFuture 更轻量、比 FutureTask 更可控,适合对响应延迟敏感、需细粒度干预阻塞行为的场景(如网关透传、实时任务编排、测试桩模拟)。关键在于:不暴露底层队列细节,不破坏 JMM 可见性,且阻塞逻辑可中断、可超时、可复用。
明确同步语义:用独占模式建模“单次完成”
AQS 的 独占模式 天然契合 Future 的“仅能完成一次”语义。state 初始化为 0,代表未完成;设为 1 表示已完成(成功或异常);不允许从 1 再变回 0。所有状态变更必须通过 compareAndSetState(0, 1) 原子执行,失败即说明已被其他线程抢先完成——这是线程安全的根基。
- 不要重写
tryAcquireShared或引入共享逻辑,Future 不支持“多个消费者同时触发完成” -
tryAcquire(int)用于阻塞前的快速判断:若 state == 1,立即返回 true,表示可直接获取结果;否则返回 false,进入等待队列 -
tryRelease(int)不需要真正“释放资源”,只负责校验调用者是否具备完成资格(比如是否是首次调用),返回 true 即可
封装阻塞逻辑:acquire() 要支持中断与超时
用户调用 get() 时,应等价于 AQS 的 acquireInterruptibly() 或 tryAcquireNanos(),而非裸调 acquire()。这意味着:
- 内部调用
acquireInterruptibly(1),让线程在等待中响应Thread.interrupt(),抛出InterruptedException - 提供
get(long timeout, TimeUnit unit)方法,底层委托给tryAcquireNanos(1, nanosTimeout),超时后自动返回或抛出TimeoutException - 阻塞期间线程处于
WAITING状态(非自旋),避免 CPU 空转;AQS 的 CLH 队列会自动管理唤醒顺序
结果存储与可见性:用 volatile + final 保障安全发布
AQS 管理的是“是否完成”的状态,但结果值本身需独立存储。推荐结构:
- 声明
private volatile Object result;和private volatile Throwable exception; - 在 CAS 成功将 state 设为 1 后,**按顺序**设置
result或exception(注意:二者互斥) - 读取时,先确认
state == 1,再读result或exception——由于state是 volatile 写,且 JVM 的 happens-before 规则保证 volatile 写之后的普通写对后续 volatile 读可见,因此无需额外同步 - 不使用
AtomicReference<Object>包裹结果,徒增开销;volatile 字段已足够
集成到 Spring Boot:作为 @Bean 注入,避免静态单例污染
不要把自定义 AQS 类做成 static 工具类或全局单例。在 Spring Boot 中应:
- 将其实现为普通 Java 类(如
OneShotLatch<T>),构造函数接收初始泛型类型信息(可选) - 通过
@Bean方法注入,例如:
@Bean
public <T> OneShotLatch<T> oneShotLatch() {
return new OneShotLatch<>();
} - 若需跨请求复用(如异步回调场景),配合
@Scope("prototype")确保每次@Autowired都获得新实例 - 避免在 Bean 初始化时就调用
complete(),防止容器启动阶段意外触发

















