Exchanger 是专为两两线程严格同步交换引用值设计的协作工具,适用于双缓冲日志、乒乓内存池等成对数据交换场景,不支持多线程广播或队列式共享。
Exchanger 是什么,适合解决哪类线程协作问题
它不是用来“广播”或“共享”数据的,而是专为**两两配对、严格同步交换**设计的。典型场景:一个线程生产缓冲区 A,另一个线程消费并填充缓冲区 B,双方在边界点互换引用——比如双缓冲日志写入、乒乓式内存池复用。
常见错误是把它当
或
用:想让多个线程任意交换,结果线程卡死在
上,因为 Exchanger 只匹配成对调用,多出的线程会一直阻塞。
必须且仅需两个线程参与一次交换;第三个线程调用
会等待前两者之一再次进入
不支持超时的配对(除非用带
的重载),没有“放弃交换”的内置机制
交换的是**引用值**,不是拷贝——双方拿到的是对方传入的同一对象,注意线程安全边界
怎么正确调用 exchange(),参数和返回值意味着什么
的签名是
,传入的是“我手上的数据”,返回的是“对方给我的数据”。它不是 void 方法,返回值必须被接收,否则交换就白做了。
容易忽略的是:即使发生中断,
也可能已完成交换才抛
。所以不能假设“抛异常 = 没交换”。
立即学习
“
Java免费学习笔记(深入)
”;
传
是合法的,但双方都传
就真交换了个空引用,别误以为是初始化信号
如果一方先调用
进入等待,另一方调用
,则前者返回
,后者返回
若超时版本
返回
,只代表超时未配对,不代表对方没调用——可能对方刚进、还没到配对点
Exchanger 在实际代码里怎么避免死锁和资源泄漏
最常踩的坑是:线程在交换前已持有锁,或交换后没清理状态,导致后续逻辑卡住。Exchanger 本身无锁,但它的使用上下文极易引入锁竞争。
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
例如用 Exchanger 协调两个工作线程交换
,但忘了重置
和
,下一轮读写直接越界或跳过数据。
交换前后务必做状态重置(如 buffer 的
、集合的
),别依赖“对方会清”
不要在 synchronized 块里调用
,否则可能造成锁顺序反转+等待链
如果某线程因异常退出,没走到下一次
,它的配对线程就会永久阻塞——需配合
或超时机制兜底
Exchanger 和其他同步工具的关键区别在哪
它和
看似都等“人齐”,但语义完全不同:
是大家到达后一起往下走;
是两人面对面交货,交完各走各路,没有“下一步统一动作”。
也别和
混:后者支持单向传递、可选阻塞/非阻塞、能排队,而 Exchanger 是硬性双向、强配对、无队列。
内部用的是 CAS + 自旋 + 队列节点,高争用下比纯锁轻量,但比无竞争的本地变量开销大得多
Java 9+ 中它仍无结构化并发支持(比如无法绑定
),异常传播需手动处理
调试时看不到“谁在等谁”,只能靠日志打点或 JFR 事件跟踪
调用栈
配对这件事,看着简单,但一旦涉及生命周期管理、异常路径、状态一致性,就很容易漏掉一环。别指望它自动兜底。
BlockingQueuePhaserexchange()exchange()timeoutexchange()V exchange(V x)exchange()InterruptedExceptionnullnullexchange(v1)exchange(v2)v2v1exchange(v, timeout, unit)nullByteBufferpositionlimitclear()clear()exchange()exchange()Thread.interrupt()CyclicBarrierCyclicBarrierExchangerTransferQueueExchangerStructuredTaskScopeexchange()