Exchanger的核心作用是为两个线程提供原子性单次数据交换,适用于高频交易中BookThread与StrategyThread按固定周期(如10ms)协同交换订单簿快照、成交价等状态的场景。

Exchanger 的核心作用与适用场景
Exchanger 是 Java 并发包中专为成对线程间单次数据交换设计的同步工具。它不适用于多线程广播或频繁轮换,但恰好契合两个高频交易线程在固定节奏(如每 10ms 一个撮合周期)后原子性交换最新状态的需求——比如订单簿快照、未成交委托、最新成交价等关键数据。
典型结构:双线程协同模型
一个线程负责实时行情处理与订单簿更新(记为 BookThread),另一个负责策略计算与下单(记为 StrategyThread)。二者严格按周期对齐:每个周期开始前,双方必须完成上一周期的数据交换,才能基于对方提供的最新状态执行本周期逻辑。
关键设计要点:
- 使用 Exchanger
作为唯一共享同步点,泛型类型封装撮合周期内需交换的核心状态(如 L2 行情快照、策略信号、挂单变化等) - 两个线程在周期末尾调用
exchange(state),阻塞直至对方也到达该点;任一线程超时未配对,应主动中断并告警,避免系统卡死 - 避免在
exchange()调用前后持有长时锁或执行耗时操作,否则会拖慢整体节拍
实战代码片段(精简关键逻辑)
定义状态类:
立即学习“Java免费学习笔记(深入)”;
public final class TradeState {
public final long timestamp;
public final Map<String, BigDecimal> bestBids; // symbol → price
public final Map<String, BigDecimal> bestAsks;
public final List<OrderSignal> signals;
<pre class="brush:php;toolbar:false;">public TradeState(long ts, Map<String,BigDecimal> bids,
Map<String,BigDecimal> asks, List<OrderSignal> sigs) {
this.timestamp = ts;
this.bestBids = Collections.unmodifiableMap(new HashMap<>(bids));
this.bestAsks = Collections.unmodifiableMap(new HashMap<>(asks));
this.signals = Collections.unmodifiableList(new ArrayList<>(sigs));
}}
线程主体逻辑(以 BookThread 为例):
Exchanger<TradeState> exchanger = new Exchanger<>();
long cycleMs = 10L;
long nextDeadline = System.nanoTime();
<p>while (running) {
// 1. 执行本周期订单簿更新、行情解析等
TradeState currentState = updateOrderBookAndGenerateState();</p><pre class="brush:php;toolbar:false;">// 2. 在周期截止前交换状态(带超时防死锁)
try {
TradeState partnerState = exchanger.exchange(
currentState, cycleMs, TimeUnit.MILLISECONDS);
// 成功交换后,partnerState 即 StrategyThread 上周期输出
handlePartnerState(partnerState);
} catch (TimeoutException e) {
log.warn("Exchange timeout at {}ns, skipping cycle", System.nanoTime());
// 可选择重试、降级使用上周期缓存,或触发熔断
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
// 3. 对齐下一周期起始时间(防止 drift)
nextDeadline += TimeUnit.MILLISECONDS.toNanos(cycleMs);
long sleepNs = nextDeadline - System.nanoTime();
if (sleepNs > 0) {
LockSupport.parkNanos(sleepNs);
}}
高频场景下的关键注意事项
Exchanger 在微秒级延迟敏感环境中需谨慎使用:
- 对象复用:避免每次 exchange 都新建 TradeState;可配合对象池(如 Apache Commons Pool 或自定义轻量池)减少 GC 压力
- 内存可见性:TradeState 内部字段建议用 final 修饰,确保发布安全;若含可变集合,务必通过 Collections.unmodifiable* 包装或使用 CopyOnWrite 容器
- 错误隔离:任一线程异常退出时,另一线程在 exchange 处将永久阻塞;需配合 Thread.UncaughtExceptionHandler + 定期心跳检测实现自动恢复
- 不替代消息队列:Exchanger 是严格 2 对 1 同步,无法扩展至多个策略线程;如需一对多分发,请改用 Disruptor 或 LMAX RingBuffer


















