exchanger是java并发包中用于两个线程成对同步交换数据的工具类,基于slot+cas实现无锁协作,核心依赖volatile字段保证内存可见性,而非物理模型或空间隐喻。

Exchanger 不是物理引擎,也没有“空间槽”或“单点碰撞”的底层物理模型。这个说法混淆了并发编程概念与物理学隐喻,Java 的 Exchanger 是一个线程间**成对同步交换数据**的工具类,其设计目标是轻量、无锁(在低竞争时)、基于 CAS 和 volatile 语义实现线程间可见性,而非模拟物理世界。
Exchanger 的真实机制:基于 Slot + CAS 的协作式交换
Exchanger 内部确实使用了一个叫 Slot 的内部类(JDK 8+),但它不是“空间位置”,而是一个**带 volatile 字段的共享状态容器**,用于暂存等待配对的线程和数据。它的核心逻辑是:
-
每个线程调用
exchange(v)时,先尝试用 CAS 把自己的数据写入共享 Slot 的item字段(该字段被声明为volatile Object item) - 若 CAS 成功,说明当前无配对线程,该线程就自旋/挂起等待;若 CAS 失败(已有其他线程占用了 Slot),则说明“撞上了”——此时直接读取对方已写入的
item,完成交换 -
volatile 的写-读语义保证了:线程 A 写入
item后,线程 B 一定能立即看到最新值,这是 JVM 内存模型规定的“happens-before”关系,不是靠“物理传递”,而是靠内存屏障指令(如 x86 的mov+lfence等效)
用原生 Java 代码直观展示可见性传递
下面这段代码不依赖任何调试器或反编译,仅用标准 JDK + volatile + Unsafe(可选)辅助验证,让初学者“看见”可见性如何发生:
import java.util.concurrent.Exchanger;
import java.util.concurrent.atomic.AtomicBoolean;
public class ExchangerVisibilityDemo {
// 模拟 Slot 的核心字段(简化版)
static class SimpleSlot {
volatile Object item; // 关键:volatile 保障可见性
volatile Thread waiter; // 记录等待线程,也需 volatile
}
public static void main(String[] args) throws InterruptedException {
Exchanger<string> ex = new Exchanger();
SimpleSlot slot = new SimpleSlot();
AtomicBoolean seenByOther = new AtomicBoolean(false);
Thread t1 = new Thread(() -> {
System.out.println("T1: 准备交换数据 \"hello\"");
try {
// T1 先写入,触发 volatile 写
slot.item = "hello";
System.out.println("T1: volatile 写入完成");
// 短暂延迟,给 T2 读取机会(非必须,仅助观察)
Thread.sleep(10);
// T1 尝试读取对方数据(模拟 Exchanger 内部逻辑)
String other = (String) slot.item; // 此时若 T2 已写入,这里能立刻看到
System.out.println("T1: 读到对方数据 = " + other);
seenByOther.set(other != null && !"hello".equals(other));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(5); // 确保 T1 先写
System.out.println("T2: 准备交换数据 \"world\"");
// T2 volatile 写入
slot.item = "world";
System.out.println("T2: volatile 写入完成");
// T2 读取(此时 T1 的 "hello" 应已被刷新到主存)
String other = (String) slot.item;
System.out.println("T2: 读到对方数据 = " + other);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("可见性是否被另一方观测到:" + seenByOther.get());
// 输出应为 true —— 证明 volatile 写对另一线程立即可见
}
}
</string>
为什么说“物理可见性传递”是误导?
Java 并发中的“可见性”是抽象的内存模型契约,不是电子信号在硅片上的传播过程:
- JVM 规范只要求 volatile 写后,后续任意线程的 volatile 读能看到该值,具体实现由 JIT 编译器和 CPU 内存序共同保证
- 现代 CPU 有缓存一致性协议(如 MESI),volatile 写会触发缓存行失效,但这对 Java 程序员是透明的——你只需相信 JMM,无需关心总线嗅探细节
- Exchanger 的 Slot 碰撞本质是**两个线程对同一 volatile 字段的竞态写-读**,不是“粒子碰撞”,更没有“空间坐标”
给初学者的建议
- 先彻底理解
volatile的 happens-before 语义,再看 Exchanger 源码(java.util.concurrent.Exchanger中的slotExchange方法) - 用
javap -c查看 volatile 字段读写的字节码,会看到getstatic/putstatic带有内存屏障语义 - 避免用物理/几何隐喻理解并发原语——它们是数学模型(如顺序一致性、释放获取语义),不是仿真系统
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











