exchanger通过同步配对机制实现两线程间对象引用的原子交换,必须成对调用exchange()才能完成交换,返回值为对方数据;需严格使用泛型、加超时控制并避免误将入参当接收值。

Exchanger 交换数据靠的是“两人碰头、一手交一手接”的同步机制,不是单向传递,也不是排队等待,而是两个线程必须同时调用 exchange() 方法,才能原子性地互换各自持有的对象引用。
交换过程是严格配对的
一个 Exchanger 实例只服务一对线程:第一个调用 exchange(data) 的线程会挂起,把 data 放进内部槽位并等待;第二个线程调用时,两者立即完成交换——A 拿到 B 的 data,B 拿到 A 的 data,然后同时继续执行。没有先后顺序,只有配对成功才解除阻塞。
- 第三个线程调用
exchange()不会和前两个中的某一个配对,而是进入新一轮等待,找它的“搭档” - 如果只有一个线程调用,它会一直阻塞,除非使用带超时的版本或被中断
- 交换的是对象引用,不是拷贝,对大数组(如
byte[])非常高效
必须用对方法签名才能拿到对方的数据
exchange() 的返回值才是对方传来的数据,不是自己传进去的那个。这是最容易出错的地方。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 写法正确:
String other = exchanger.exchange("from-A");→ other 是线程 B 传来的值 - 常见错误:把入参 "from-A" 当作接收到的数据,实际它只是发出的内容
- 泛型类型两端必须一致,比如都声明为
Exchanger<int></int>,否则运行时强转可能失败
生产环境一定要加超时控制
不设超时的 exchange(data) 在线程异常退出、逻辑跳过或启动失败时,会导致另一方永久挂起,极易引发系统卡死。
- 推荐始终使用带超时的重载:
exchanger.exchange(data, 2, TimeUnit.SECONDS) - 超时抛出
TimeoutException,可做降级处理,比如记录告警、释放资源、重试或跳过本轮 - 捕获
InterruptedException后应恢复中断状态:Thread.currentThread().interrupt();
适合交换的典型数据形态
Exchanger 不适合传小字符串或临时对象,它的优势在于复用大块内存或状态容器。
- 双缓冲区:渲染线程填满
backBuffer,显示线程交出frontBuffer,交换后各取所需 - 采集与处理分离:采集线程交出已填满的
dataBlock,处理线程交回已解析完的空块 - 中间结果协同:两线程分别计算子任务,交换结果后交叉验证或合并
- 允许传
null,但需双方明确约定语义,避免空指针或逻辑歧义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










