Exchanger是专为两个线程设计的同步交换器,要求严格一对一配对、碰头即换、无内部缓冲,适用于双缓冲流水线等场景;不支持多线程、广播或轮换,需用泛型保证类型安全,并推荐使用带超时的exchange方法以提升健壮性。

Exchanger 是专为两个线程设计的同步交换器,不是队列、不是广播通道,而是一个“碰头即换”的协作点。它让生产者和消费者在确定的汇合位置安全移交缓冲区引用,避免锁竞争、内存可见性问题和额外拷贝,特别适合双缓冲流水线场景。
必须严格一对一配对
Exchanger 只接受且仅能完成两个线程之间的交换。第三个线程调用 exchange() 会永久阻塞——因为它内部没有等待队列,也不支持重入或轮换。常见错误包括:
- 用线程池(如
FixedThreadPool(2))提交任务:线程可能被复用,导致上一轮未配对的等待残留 - 启动两个生产者线程:双方都在等“那个唯一的消费者”,结果双双挂起
- 每次新建 Exchanger 实例:破坏线程间共享状态,交换无法成立
缓冲区生命周期要闭环管理
交换本身只传递引用,不复制数据,因此缓冲区的状态(position、limit、mark)必须由线程自己维护。典型流程中,每轮操作后必须重置:
- 生产者侧:填满数据 →
buf.flip()→exchanger.exchange(buf)→buf.clear() - 消费者侧:接收缓冲区 → 处理数据 →
buf.clear()(或compact(),视需求而定) - 切忌在
exchange()前后插入耗时操作(如日志打印、磁盘写入),否则会拉长等待窗口,掩盖真实瓶颈
推荐使用带超时的 exchange 方法
无限等待的 exchange(V) 在生产环境风险较高。建议统一采用带超时版本,主动控制协作失败边界:
-
exchanger.exchange(buf, 5, TimeUnit.SECONDS)—— 超时抛TimeoutException,可触发重试、告警或优雅降级 - 捕获
InterruptedException后应清理资源并退出循环,避免线程处于不可预期状态 - 超时时间需结合业务处理耗时设定,不宜过短(频繁超时)或过长(故障响应迟钝)
类型安全与泛型约束不能忽略
声明时必须明确泛型类型,例如 Exchanger<bytebuffer></bytebuffer>。若一个线程传 ByteBuffer,另一个传 byte[],运行时强转会失败。实际使用中建议:
- 共用同一缓冲区类型(如都用
ByteBuffer或都用byte[]) - 避免传
null,除非双方明确约定(如消费者初始化时用exchanger.exchange(null)获取首个缓冲区) - 缓冲区实例应在各自线程内创建并长期持有,不跨轮次 new 新对象,减少 GC 压力

















