Exchanger仅支持严格的一对一线程协作,不支持三者及以上共享同一实例,否则第三个线程将永久阻塞;典型应用是双缓冲流水线中渲染与显示线程交换ByteBuffer引用,需使用带超时的exchange()并确保类型安全与缓冲区状态自管理。

Exchanger 不是通用同步通道,它只支持严格的一对一线程协作。所谓“多线程协作”,必须理解为多个独立的线程对(即多组两两配对),而非多个线程共享同一个 Exchanger 实例。
必须成对使用,不支持三者及以上
一个 Exchanger 实例内部没有等待队列,也不做轮换调度。当第三个线程调用 exchange() 时,它不会和前两个中的某一个“接力”交换,而是永久阻塞——因为前两次交换已使内部状态归零,它找不到配对者。
- 错误做法:用固定大小为 3 的线程池共用一个 Exchanger → 必然卡住一个线程
- 正确做法:每对协作线程独占一个 Exchanger 实例,或按业务逻辑拆分为明确的 A-B、C-D 等配对关系
- 若需一对多或广播,应换用其他工具,如 Phaser 或 BlockingQueue + 分发逻辑
双缓冲流水线是典型落地场景
渲染线程与显示线程交换 ByteBuffer 引用是最常见的应用之一。双方各自持有缓冲区,填满后调用 exchange(),拿到对方刚处理完的缓冲区继续工作,全程无拷贝、无锁竞争。
- 生产者侧流程:写入数据 → buf.flip() → exchanger.exchange(buf) → buf.clear()
- 消费者侧流程:接收 buf → 处理数据 → buf.clear()(或 compact())
- 关键点:缓冲区对象应在各自线程内长期复用,避免每轮 new,减少 GC 压力
务必启用超时机制保障系统健壮性
使用无参 exchange(V) 在生产环境风险极高。一旦某线程因异常退出、死循环或未启动,另一方将无限等待,导致资源泄漏甚至服务不可用。
- 推荐统一使用带超时版本:exchange(buf, 3, TimeUnit.SECONDS)
- 超时后捕获 TimeoutException,可触发告警、重试或降级逻辑
- 同时需响应 InterruptedException,及时清理资源并退出协作循环
类型安全与对象生命周期要全程受控
泛型声明决定实际可交换的数据类型,运行时强转失败会抛出 ClassCastException;而交换仅传递引用,不复制内容,因此缓冲区的状态(如 position、limit)必须由线程自己维护。
- 声明时明确类型:如 Exchanger<ByteBuffer>,禁止混用 byte[] 和 ByteBuffer
- 切忌把 received 当作本地处理结果——它是对方传来的数据,不是你刚填的内容
- 避免在 exchange() 前后插入耗时操作(如日志、IO),否则拉长等待窗口,掩盖真实性能瓶颈

















