JDK 8 Exchanger 源码详解(详细注释版)
1. 类定义和基本属性
public class Exchanger<V> implements java.io.Serializable {
// 序列化版本号
private static final long serialVersionUID = -3223113410248163686L;
/**
* Exchanger的核心设计思想:
*
* 1. 对称数据交换:
* - 两个线程通过Exchanger交换数据
* - 提供原子性的数据交换操作
* - 支持阻塞和超时等待
*
* 2. 高效的交换机制:
* - 使用CAS操作实现无锁化
* - 支持多槽位减少竞争
* - 优化的内存布局
*
* 3. 线程安全:
* - 所有操作都是线程安全的
* - 支持高并发环境
* - 无死锁风险
*
* 4. 灵活的等待机制:
* - 支持无限期等待
* - 支持可中断等待
* - 支持超时等待
* - 提供多种等待选项
*
* 5. 内存优化:
* - 使用ThreadLocal减少竞争
* - 优化的对象创建和回收
* - 及时的垃圾回收
*
* 适用场景:
* - 生产者-消费者模式的数据交换
* - 线程间的数据传递
* - 需要双向数据交换的场景
* - 实现管道或通道的场景
* - 需要原子性数据交换的场景
*/
2. 内部节点类(详细注释)
/**
* 线程本地节点,用于存储线程的交换信息
* 每个线程都有自己的Node实例,减少竞争
*/
static final class Node {
/**
* 要交换的数据
* 当前线程要传递给对方线程的数据
*/
Object item;
/**
* 从对方线程接收到的数据
* 交换完成后存储对方线程传递的数据
*/
volatile Object data;
/**
* 匹配的线程节点
* 指向与当前线程进行交换的对方线程节点
*/
volatile Node match;
/**
* 线程等待时的自旋次数
* 用于控制自旋等待的时间
*/
volatile int spins;
/**
* 等待队列中的下一个节点
* 形成等待队列的链表结构
*/
volatile Node next;
/**
* 等待队列中的前一个节点
* 用于双向链表操作
*/
volatile Node prev;
/**
* 线程关联的Exchanger实例
* 用于跨Exchanger实例的区分
*/
volatile Exchanger<?> owner;
/**
* 构造方法
* @param item 要交换的数据
*/
Node(Object item) {
this.item = item;
}
/**
* 构造方法(用于槽位节点)
* @param owner 关联的Exchanger实例
*/
Node(Exchanger<?> owner) {
this.owner = owner;
}
}
/**
* 槽位节点数组
* 用于减少线程竞争,提高并发性能
* 通过哈希分布将线程分散到不同的槽位
*/
private volatile Node[] arena;
/**
* 槽位数量的位移量
* 用于计算哈希索引
*/
private static final int ASHIFT = 7;
/**
* 槽位数量掩码
* 用于计算哈希索引
*/
private static final int MMASK = 0x7f;
/**
* 最大槽位数量
* 限制槽数组的大小
*/
private static final int FULL = 0x80;
/**
* 线程本地变量,用于存储每个线程的节点
* 减少对象创建和垃圾回收的开销
*/
private final ThreadLocal<Node> participant = new ThreadLocal<Node>() {
protected Node initialValue() {
return new Node(null);
}
};
/**
* 获取线程本地节点
* @return 当前线程的节点
*/
private Node newNode(Object item) {
Node n = participant.get();
n.item = item;
n.data = null;
n.match = null;
n.spins = 0;
n.next = null;
n.prev = null;
n.owner = this;
return n;
}
/**
* 重置线程本地节点
* @param n 要重置的节点
*/
private void reuseNode(Node n) {
n.item = null;
n.data = null;
n.match = null;
n.spins = 0;
n.next = null;
n.prev = null;
n.owner = this;
}
3. 核心交换方法(详细注释)
/**
* 交换数据
* 当前线程会阻塞直到另一个线程调用exchange方法
*
* 交换过程:
* 1. 创建当前线程的节点
* 2. 寻找匹配的线程节点
* 3. 如果找到匹配节点,进行数据交换
* 4. 如果没有找到匹配节点,进入等待状态
* 5. 被匹配线程唤醒后完成数据交换
* 6. 返回从对方线程接收到的数据
*
* 阻塞特性:
* - 如果没有其他线程等待,当前线程会阻塞
* - 直到另一个线程调用exchange方法
* - 交换完成后两个线程同时返回
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
* 线程安全性:完全线程安全
*
* @param x 要交换的数据
* @return 从对方线程接收到的数据
* @throws InterruptedException 如果线程被中断
*
* 使用场景:
* - 生产者-消费者数据交换
* - 线程间的数据传递
* - 实现管道或通道
* - 需要原子性数据交换的场景
*/
public V exchange(V x) throws InterruptedException {
// 如果线程被中断,直接抛出异常
if (Thread.interrupted())
throw new InterruptedException();
// 创建当前线程的节点
Node n = newNode(x);
// 调用核心交换方法
Object v = doExchange(n, false, 0);
// 如果返回的是中断标记,抛出异常
if (v == n)
throw new InterruptedException();
// 返回从对方线程接收到的数据
@SuppressWarnings("unchecked")
V vv = (V) v;
return vv;
}
/**
* 交换数据(带超时)
* 当前线程会在指定时间内等待另一个线程调用exchange方法
*
* 超时处理:
* 1. 创建当前线程的节点
* 2. 寻找匹配的线程节点
* 3. 如果找到匹配节点,进行数据交换
* 4. 如果没有找到匹配节点,进入等待状态
* 5. 在指定时间内等待匹配线程
* 6. 超时后如果仍没有匹配线程,抛出TimeoutException
* 7. 被匹配线程唤醒后完成数据交换
*
* 时间处理:
* - 将时间单位转换为纳秒
* - 使用高精度计时
* - 支持任意时间单位
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
* 线程安全性:完全线程安全
*
* @param x 要交换的数据
* @param timeout 等待时间
* @param unit 时间单位
* @return 从对方线程接收到的数据
* @throws InterruptedException 如果线程被中断
* @throws TimeoutException 如果等待超时
*
* 使用场景:
* - 带超时的生产者-消费者数据交换
* - 避免无限期等待
* - 实现超时控制
* - 需要时间限制的数据交换
*/
public V exchange(V x, long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException {
// 如果线程被中断,直接抛出异常
if (Thread.interrupted())
throw new InterruptedException();
// 创建当前线程的节点
Node n = newNode(x);
// 转换超时时间为纳秒
Object v = doExchange(n, true, unit.toNanos(timeout));
// 如果返回的是中断标记,抛出异常
if (v == n)
throw new InterruptedException();
// 如果返回的是超时标记,抛出超时异常
else if (v == TIMED_OUT)
throw new TimeoutException();
// 返回从对方线程接收到的数据
@SuppressWarnings("unchecked")
V vv = (V) v;
return vv;
}
/**
* 超时标记
* 用于标识超时情况
*/
private static final Object TIMED_OUT = new Object();
/**
* 中断标记
* 用于标识中断情况
*/
private static final Object INTERRUPTED = new Object();
4. 核心交换实现(详细注释)
/**
* 实际的交换操作
* 实现Exchanger的核心交换逻辑
*
* 交换算法:
* 1. 使用多槽位机制减少竞争
* 2. 通过哈希分布将线程分散到不同槽位
* 3. 在槽位中寻找匹配的线程节点
* 4. 如果找到匹配节点,进行数据交换
* 5. 如果没有找到匹配节点,进入等待状态
* 6. 被匹配线程唤醒后完成数据交换
*
* 多槽位优势:
* - 减少线程竞争
* - 提高并发性能
* - 优化内存访问局部性
* - 支持更高的吞吐量
*
* @param node 当前线程的节点
* @param timed 是否使用超时
* @param nanos 超时时间(纳秒)
* @return 交换结果
*/
private Object doExchange(Node node, boolean timed, long nanos) {
// 获取当前线程
Thread me = Thread.currentThread();
// 获取槽位数组
Node[] a = arena;
// 计算哈希索引
int index = hashIndex();
// 自旋次数
int spins = SPINS;
// 无限循环,直到交换完成
for (;;) {
// 如果槽位数组为空,初始化
if (a == null) {
a = arena = new Node[MMASK + 1];
index = hashIndex();
}
// 获取槽位中的节点
Node slot = a[index];
// 如果槽位为空
if (slot == null) {
// 尝试将当前节点放入槽位
if (compareAndSetSlot(a, index, null, node)) {
// 成功放入槽位,等待匹配
return awaitMatch(node, timed, nanos);
}
}
// 如果槽位中的节点属于其他Exchanger实例
else if (slot.owner != this) {
// 创建新的槽位数组
a = arena = new Node[MMASK + 1];
index = hashIndex();
}
// 如果槽位中有等待的节点
else if (spins > 0) {
// 自旋等待
spins = decrementSpins(spins);
}
// 如果槽位中有等待的节点且自旋结束
else {
// 尝试与槽位中的节点进行交换
if (slot != node && tryMatch(slot, node)) {
// 交换成功,返回结果
return node.data;
}
// 如果槽位满了
else if (a[FULL] != null) {
// 等待槽位空闲
return awaitMatch(node, timed, nanos);
}
// 将当前节点放入槽位
else if (compareAndSetSlot(a, index, slot, node)) {
// 等待匹配
return awaitMatch(node, timed, nanos);
}
}
}
}
/**
* 计算哈希索引
* 通过线程ID计算哈希值,将线程分散到不同槽位
* @return 哈希索引
*/
private int hashIndex() {
// 获取线程ID的低7位作为哈希索引
return (int) (Thread.currentThread().getId() & MMASK);
}
/**
* CAS操作更新槽位
* @param a 槽位数组
* @param i 索引
* @param cmp 预期值
* @param val 新值
* @return 如果更新成功返回true,否则返回false
*/
private boolean compareAndSetSlot(Node[] a, int i, Node cmp, Node val) {
// 使用Unsafe进行CAS操作
return UNSAFE.compareAndSwapObject(a, ((long)i << ASHIFT) + ABASE, cmp, val);
}
/**
* 尝试与对方节点进行匹配
* @param slot 槽位中的节点
* @param node 当前节点
* @return 如果匹配成功返回true,否则返回false
*/
private boolean tryMatch(Node slot, Node node) {
// 设置匹配关系
node.match = slot;
// CAS操作更新槽位
if (compareAndSetSlot(arena, hashIndex(), slot, node)) {
// 唤醒等待的线程
LockSupport.unpark(slot.waiter);
return true;
}
return false;
}
/**
* 等待匹配
* 当前线程进入等待状态直到被匹配
* @param node 当前节点
* @param timed 是否使用超时
* @param nanos 超时时间(纳秒)
* @return 交换结果
*/
private Object awaitMatch(Node node, boolean timed, long nanos) {
// 设置等待线程
node.waiter = Thread.currentThread();
// 开始等待
Object x = node.item;
// 计算超时时间
long lastTime = timed ? System.nanoTime() : 0L;
// 无限循环等待匹配
while (x == node.item) {
// 检查线程是否被中断
if (Thread.interrupted()) {
// 取消等待
cancelWait(node);
return node;
}
// 检查是否超时
if (timed) {
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
if (nanos <= 0) {
// 超时,取消等待
cancelWait(node);
return TIMED_OUT;
}
// 阻塞等待指定时间
LockSupport.parkNanos(this, nanos);
} else {
// 无限期阻塞等待
LockSupport.park(this);
}
// 检查匹配结果
if (node.match != null) {
// 匹配成功,获取数据
x = node.data;
}
}
return x;
}
/**
* 取消等待
* 当线程被中断或超时时调用
* @param node 要取消等待的节点
*/
private void cancelWait(Node node) {
// 从槽位中移除节点
Node[] a = arena;
if (a != null) {
int index = hashIndex();
Node slot = a[index];
if (slot == node) {
compareAndSetSlot(a, index, slot, null);
}
}
// 唤醒可能等待的线程
LockSupport.unpark(node.waiter);
}
/**
* 减少自旋次数
* @param spins 当前自旋次数
* @return 减少后的自旋次数
*/
private int decrementSpins(int spins) {
return (spins & SPINS) == 0 ? 0 : spins - 1;
}
/**
* 自旋次数常量
*/
private static final int SPINS = (1 << 8) - 1;
/**
* 等待线程
*/
volatile Thread waiter;
5. Unsafe相关字段和方法(详细注释)
/**
* Unsafe类实例
* 提供底层的原子操作
*/
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
/**
* 数组基地址
*/
private static final long ABASE;
/**
* 获取Unsafe实例
* @return Unsafe实例
*/
private static sun.misc.Unsafe getUnsafe() {
try {
return sun.misc.Unsafe.getUnsafe();
} catch (SecurityException se) {
try {
return java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
for (java.lang.reflect.Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x))
return k.cast(x);
}
throw new NoSuchFieldError("the Unsafe");
}});
} catch (java.security.PrivilegedActionException e) {
throw new RuntimeException("Could not initialize intrinsics",
e.getCause());
}
}
}
/**
* 静态初始化块
*/
static {
try {
ABASE = UNSAFE.arrayBaseOffset(Node[].class);
int scale = UNSAFE.arrayIndexScale(Node[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
// 省略具体的初始化代码
} catch (Exception e) {
throw new Error(e);
}
}
6. Exchanger 的特点分析
核心设计理念:
/**
* Exchanger的核心设计思想:
*
* 1. 对称数据交换:
* - 两个线程通过Exchanger交换数据
* - 提供原子性的数据交换操作
* - 支持阻塞和超时等待
* - 保证交换的原子性和一致性
*
* 2. 多槽位机制:
* - 使用多个槽位减少线程竞争
* - 通过哈希分布将线程分散到不同槽位
* - 提高并发性能和吞吐量
* - 优化内存访问局部性
*
* 3. 无锁设计:
* - 使用CAS操作实现无锁化
* - 减少传统锁的开销和阻塞
* - 提供乐观锁机制
* - 支持高并发环境
*
* 4. 线程本地存储:
* - 每个线程维护自己的Node节点
* - 减少对象创建和垃圾回收开销
* - 优化内存使用
* - 提高性能
*
* 5. 灵活的等待机制:
* - 支持无限期等待
* - 支持可中断等待
* - 支持超时等待
* - 提供多种等待选项
*
* 6. 高效的交换算法:
* - 快速匹配机制
* - 优化的内存布局
* - 高效的线程调度
* - 及时的垃圾回收
*
* 7. 内存优化:
* - 及时清理不用的节点
* - 重用Node对象
* - 避免内存泄漏
* - 优化GC性能
*
* 适用场景:
* - 生产者-消费者模式的数据交换
* - 线程间的数据传递
* - 实现管道或通道
* - 需要原子性数据交换的场景
* - 高并发环境下的数据交换
* - 需要双向数据交换的场景
*/
性能特征分析:
/**
* Exchanger的性能特征:
*
* 时间复杂度:
* - exchange(x): O(1) 平均情况,O(∞) 最坏情况(等待时间)
* - exchange(x, timeout, unit): O(1) 平均情况,O(∞) 最坏情况(等待时间)
*
* 空间复杂度:
* - O(n) 等待队列空间(n为等待线程数)
* - O(m) 槽位数组空间(m为槽数组大小)
* - 每个实例固定开销较小
*
* 并发特性:
* - 完全线程安全
* - 支持高并发读写
* - 无死锁风险
* - 支持可重入性
*
* 多槽位优势:
* - 减少线程竞争:多个槽位分散线程
* - 提高吞吐量:并行处理多个交换
* - 优化性能:减少CAS竞争
* - 支持扩展:动态调整槽数量
*
* 与SynchronousQueue对比:
* - Exchanger: 双向数据交换,两个线程交换数据
* - SynchronousQueue: 单向数据传递,生产者传递给消费者
* - Exchanger: 支持超时和中断
* - SynchronousQueue: 更简单的传递语义
*
* 内存使用:
* - 每个实例固定开销较小
* - 等待线程会增加内存使用
* - 及时GC,避免内存泄漏
* - 线程本地存储优化内存使用
*
* 适用性:
* - 双向数据交换:性能优异
* - 简单数据传递:可能不如SynchronousQueue
* - 高并发交换:性能优异
* - 需要超时控制:支持完善
* - 需要中断支持:支持完善
*
* 性能优化:
* - 合理设置槽数量
* - 避免不必要的等待
* - 使用超时机制避免无限等待
* - 正确处理中断异常
* - 监控等待线程数量
* - 优化自旋次数
*/
7. 使用示例和最佳实践
/**
* 使用示例:
*
* // 基本使用:生产者-消费者数据交换
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 生产者线程
* Thread producer = new Thread(() -> {
* try {
* String dataToSend = "Hello from producer";
* System.out.println("Producer sending: " + dataToSend);
* String receivedData = exchanger.exchange(dataToSend);
* System.out.println("Producer received: " + receivedData);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* // 消费者线程
* Thread consumer = new Thread(() -> {
* try {
* String dataToSend = "Hello from consumer";
* System.out.println("Consumer sending: " + dataToSend);
* String receivedData = exchanger.exchange(dataToSend);
* System.out.println("Consumer received: " + receivedData);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* producer.start();
* consumer.start();
*
* // 带超时的数据交换示例
* Exchanger<Integer> timeoutExchanger = new Exchanger<>();
*
* Thread sender = new Thread(() -> {
* try {
* Integer data = 42;
* System.out.println("Sender exchanging: " + data);
* Integer received = timeoutExchanger.exchange(data, 5, TimeUnit.SECONDS);
* System.out.println("Sender received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } catch (TimeoutException e) {
* System.out.println("Sender timed out");
* }
* });
*
* Thread receiver = new Thread(() -> {
* try {
* Thread.sleep(3000); // 模拟延迟
* Integer data = 100;
* System.out.println("Receiver exchanging: " + data);
* Integer received = timeoutExchanger.exchange(data, 5, TimeUnit.SECONDS);
* System.out.println("Receiver received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } catch (TimeoutException e) {
* System.out.println("Receiver timed out");
* }
* });
*
* sender.start();
* receiver.start();
*
* // 多对数据交换示例
* class DataExchangePipeline {
* private final Exchanger<String> exchanger1 = new Exchanger<>();
* private final Exchanger<String> exchanger2 = new Exchanger<>();
*
* public void startPipeline() {
* // 第一阶段线程
* Thread stage1 = new Thread(() -> {
* try {
* String input = "Input data";
* String processed = "Processed: " + input;
* System.out.println("Stage 1: " + processed);
* String result = exchanger1.exchange(processed);
* System.out.println("Stage 1 received: " + result);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* // 第二阶段线程
* Thread stage2 = new Thread(() -> {
* try {
* String input = "Stage 2 data";
* System.out.println("Stage 2: " + input);
* String result1 = exchanger1.exchange(input);
* System.out.println("Stage 2 received from Stage 1: " + result1);
*
* String processed = "Final: " + result1 + " + " + input;
* String result2 = exchanger2.exchange(processed);
* System.out.println("Stage 2 received final: " + result2);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* // 第三阶段线程
* Thread stage3 = new Thread(() -> {
* try {
* String input = "Output data";
* System.out.println("Stage 3: " + input);
* String result = exchanger2.exchange(input);
* System.out.println("Stage 3 received: " + result);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* stage1.start();
* stage2.start();
* stage3.start();
* }
* }
*
* // 缓冲区交换示例
* class BufferExchanger {
* private final Exchanger<List<String>> exchanger = new Exchanger<>();
* private final List<String> fillBuffer = new ArrayList<>();
* private final List<String> emptyBuffer = new ArrayList<>();
*
* public void startProducer() {
* Thread producer = new Thread(() -> {
* try {
* for (int i = 0; i < 100; i++) {
* fillBuffer.add("Item " + i);
* if (fillBuffer.size() >= 10) {
* System.out.println("Producer exchanging full buffer");
* List<String> exchanged = exchanger.exchange(fillBuffer);
* fillBuffer.clear();
* // 使用交换回来的空缓冲区
* emptyBuffer.addAll(exchanged);
* }
* }
* // 发送最后一个缓冲区
* if (!fillBuffer.isEmpty()) {
* List<String> exchanged = exchanger.exchange(fillBuffer);
* fillBuffer.clear();
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
* producer.start();
* }
*
* public void startConsumer() {
* Thread consumer = new Thread(() -> {
* try {
* while (true) {
* System.out.println("Consumer exchanging empty buffer");
* List<String> exchanged = exchanger.exchange(emptyBuffer);
* // 处理接收到的填充缓冲区
* for (String item : exchanged) {
* System.out.println("Processing: " + item);
* }
* exchanged.clear();
* // 使用交换回来的空缓冲区
* emptyBuffer.addAll(exchanged);
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
* consumer.start();
* }
* }
*
* 最佳实践:
*
* 1. 正确处理中断异常:
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 正确的做法:处理中断异常
* try {
* String data = "Hello";
* String received = exchanger.exchange(data);
* System.out.println("Received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt(); // 恢复中断状态
* System.out.println("Exchange interrupted");
* }
*
* // 错误的做法:忽略中断异常
* // String received = exchanger.exchange("Hello"); // 没有处理异常
*
* 2. 合理使用超时机制:
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 使用超时避免无限等待
* try {
* String data = "Hello";
* String received = exchanger.exchange(data, 5, TimeUnit.SECONDS);
* System.out.println("Received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* System.out.println("Exchange interrupted");
* } catch (TimeoutException e) {
* System.out.println("Exchange timed out");
* // 处理超时情况
* }
*
* 3. 避免死锁:
* Exchanger<String> exchanger1 = new Exchanger<>();
* Exchanger<String> exchanger2 = new Exchanger<>();
*
* // 错误的做法:可能导致死锁
* // Thread t1 = new Thread(() -> {
* // try {
* // String data1 = exchanger1.exchange("data1");
* // String data2 = exchanger2.exchange("data2"); // 可能与另一个线程形成死锁
* // } catch (InterruptedException e) {
* // Thread.currentThread().interrupt();
* // }
* // });
* //
* // Thread t2 = new Thread(() -> {
* // try {
* // String data2 = exchanger2.exchange("data2"); // 可能与另一个线程形成死锁
* // String data1 = exchanger1.exchange("data1");
* // } catch (InterruptedException e) {
* // Thread.currentThread().interrupt();
* // }
* // });
*
* // 正确的做法:保持一致的交换顺序
* Thread t1 = new Thread(() -> {
* try {
* String data1 = exchanger1.exchange("data1");
* String data2 = exchanger1.exchange("data2"); // 保持相同的交换顺序
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* Thread t2 = new Thread(() -> {
* try {
* String data1 = exchanger1.exchange("data1"); // 保持相同的交换顺序
* String data2 = exchanger1.exchange("data2");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* 4. 正确处理数据类型:
* Exchanger<List<String>> exchanger = new Exchanger<>();
*
* // 使用不可变数据避免副作用
* List<String> data = Collections.unmodifiableList(Arrays.asList("item1", "item2"));
* try {
* List<String> received = exchanger.exchange(data);
* System.out.println("Received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* // 或者使用防御性复制
* List<String> mutableData = new ArrayList<>(Arrays.asList("item1", "item2"));
* List<String> immutableData = new ArrayList<>(mutableData);
* try {
* List<String> received = exchanger.exchange(immutableData);
* System.out.println("Received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* 5. 合理设置超时时间:
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 根据业务需求设置合理的超时时间
* long timeout = calculateAppropriateTimeout(); // 根据实际情况计算
* try {
* String data = "Hello";
* String received = exchanger.exchange(data, timeout, TimeUnit.MILLISECONDS);
* System.out.println("Received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } catch (TimeoutException e) {
* System.out.println("Exchange timed out after " + timeout + " ms");
* // 处理超时情况
* }
*
* private long calculateAppropriateTimeout() {
* // 根据业务逻辑和系统性能计算合适的超时时间
* return 10000; // 10秒
* }
*
* 6. 监控和调试:
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 在生产环境中添加监控
* public String monitoredExchange(String data) throws InterruptedException {
* long startTime = System.nanoTime();
* try {
* String received = exchanger.exchange(data);
* long endTime = System.nanoTime();
* long duration = endTime - startTime;
* System.out.println("Exchange completed in " + duration + " ns");
* return received;
* } catch (InterruptedException e) {
* long endTime = System.nanoTime();
* long duration = endTime - startTime;
* System.out.println("Exchange interrupted after " + duration + " ns");
* throw e;
* }
* }
*
* 7. 异常处理:
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 全面的异常处理
* public void robustExchange(String data) {
* try {
* String received = exchanger.exchange(data);
* processReceivedData(received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* handleInterruption();
* } catch (Exception e) {
* handleError(e);
* }
* }
*
* private void processReceivedData(String data) {
* // 处理接收到的数据
* System.out.println("Processing: " + data);
* }
*
* private void handleInterruption() {
* System.out.println("Exchange was interrupted");
* // 执行清理操作
* cleanupResources();
* }
*
* private void handleError(Exception e) {
* System.err.println("Error during exchange: " + e.getMessage());
* // 记录日志或执行其他错误处理
* logError(e);
* }
*
* private void cleanupResources() {
* // 清理资源
* System.out.println("Cleaning up resources");
* }
*
* private void logError(Exception e) {
* // 记录错误日志
* System.err.println("Error logged: " + e.getMessage());
* }
*
* 8. 性能调优:
* // 在高并发场景下优化性能
* Exchanger<String> exchanger = new Exchanger<>();
*
* // 使用线程池管理线程
* ExecutorService executor = Executors.newFixedThreadPool(10);
*
* // 批量提交任务
* for (int i = 0; i < 100; i++) {
* final int taskId = i;
* executor.submit(() -> {
* try {
* String data = "Task " + taskId + " data";
* String received = exchanger.exchange(data);
* System.out.println("Task " + taskId + " received: " + received);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
* }
*
* // 优雅关闭
* executor.shutdown();
* try {
* if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
* executor.shutdownNow();
* }
* } catch (InterruptedException e) {
* executor.shutdownNow();
* Thread.currentThread().interrupt();
* }
*
* 9. 资源管理:
* class ManagedExchanger<T> {
* private final Exchanger<T> exchanger = new Exchanger<>();
* private final AtomicBoolean closed = new AtomicBoolean(false);
*
* public T exchange(T data) throws InterruptedException {
* if (closed.get()) {
* throw new IllegalStateException("Exchanger is closed");
* }
* return exchanger.exchange(data);
* }
*
* public T exchange(T data, long timeout, TimeUnit unit)
* throws InterruptedException, TimeoutException {
* if (closed.get()) {
* throw new IllegalStateException("Exchanger is closed");
* }
* return exchanger.exchange(data, timeout, unit);
* }
*
* public void close() {
* if (closed.compareAndSet(false, true)) {
* System.out.println("Exchanger closed");
* // 执行清理操作
* }
* }
* }
*
* 10. 测试和验证:
* // 编写测试用例验证Exchanger的正确性
* class ExchangerTest {
* @Test
* public void testBasicExchange() throws InterruptedException {
* Exchanger<String> exchanger = new Exchanger<>();
* CountDownLatch latch = new CountDownLatch(2);
* AtomicReference<String> result1 = new AtomicReference<>();
* AtomicReference<String> result2 = new AtomicReference<>();
*
* Thread t1 = new Thread(() -> {
* try {
* String received = exchanger.exchange("from-t1");
* result1.set(received);
* latch.countDown();
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* Thread t2 = new Thread(() -> {
* try {
* String received = exchanger.exchange("from-t2");
* result2.set(received);
* latch.countDown();
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* t1.start();
* t2.start();
*
* latch.await(5, TimeUnit.SECONDS);
*
* assertEquals("from-t2", result1.get());
* assertEquals("from-t1", result2.get());
* }
* }
*/
8. 与其他同步机制的比较
/**
* Exchanger vs SynchronousQueue vs BlockingQueue vs CountDownLatch:
*
* Exchanger:
* - 双向数据交换
* - 两个线程交换数据
* - 支持超时和中断
* - 原子性数据交换
* - 适用于需要双向通信的场景
*
* SynchronousQueue:
* - 单向数据传递
* - 生产者传递给消费者
* - 不存储元素
* - 最低延迟,最高吞吐量
* - 适用于直接传递的场景
*
* BlockingQueue:
* - 单向数据存储和传递
* - 支持多个生产者和消费者
* - 可以存储多个元素
* - 支持有界和无界队列
* - 适用于缓冲和排队的场景
*
* CountDownLatch:
* - 计数器机制
* - 一个或多个线程等待其他线程完成
* - 一次性使用
* - 不支持数据交换
* - 适用于协调多个线程的场景
*
* 性能对比:
* - 简单传递:SynchronousQueue > Exchanger > BlockingQueue > CountDownLatch
* - 双向交换:Exchanger > SynchronousQueue > BlockingQueue > CountDownLatch
* - 多线程协调:CountDownLatch > BlockingQueue > Exchanger > SynchronousQueue
* - 数据缓冲:BlockingQueue > Exchanger > SynchronousQueue > CountDownLatch
* - 内存使用:SynchronousQueue < Exchanger < BlockingQueue < CountDownLatch
*
* 选择建议:
* - 双向数据交换:Exchanger
* - 直接传递:SynchronousQueue
* - 数据缓冲:BlockingQueue
* - 线程协调:CountDownLatch
* - 读写分离:ReentrantReadWriteLock
* - 复杂同步:ReentrantLock
*
* 使用场景:
* - Exchanger:生产者-消费者数据交换、管道实现、双向通信
* - SynchronousQueue:直接传递、线程池任务传递
* - BlockingQueue:缓冲区、任务队列、消息传递
* - CountDownLatch:主线程等待子线程完成、启动门闩、关闭门闩
*
* 线程安全性:
* - 所有机制都提供完全的线程安全性
* - Exchanger和SynchronousQueue支持高并发
* - BlockingQueue支持生产者消费者模式
* - CountDownLatch支持协调同步
*
* 功能丰富度:
* - Exchanger:支持超时、中断、双向交换
* - SynchronousQueue:简单直接传递
* - BlockingQueue:丰富的队列操作
* - CountDownLatch:简单的计数器操作
*/
9. 总结
ReentrantReadWriteLock 的核心特性:
-
读写分离:
- 读锁:共享锁,多个读线程可以同时持有
- 写锁:独占锁,写线程独占访问
- 读读不互斥,读写互斥,写写互斥
-
可重入性:
- 支持读锁和写锁的可重入
- 每个线程维护自己的持有计数
- 完全释放时才允许其他线程获取
-
锁降级:
- 支持写锁降级为读锁
- 先获取写锁,再获取读锁,最后释放写锁
- 保证数据的一致性
-
公平性选择:
- 提供公平和非公平两种模式
- 公平锁避免线程饥饿
- 非公平锁提高性能
-
线程本地存储:
- 使用ThreadLocal跟踪每个线程的读锁持有情况
- 避免竞争和同步开销
- 优化单个读线程的场景
-
AQS集成:
- 继承AbstractQueuedSynchronizer
- 复用成熟的队列管理机制
- 提供完整的同步框架
-
Condition支持:
- 写锁支持Condition
- 提供灵活的线程等待/通知机制
- 不支持读锁的Condition
-
丰富的查询API:
- 提供详细的锁状态查询
- 支持监控和诊断
- 便于调试和性能调优
适用场景:
- 读操作远多于写操作的场景
- 需要高并发读取的场景
- 需要比ReentrantLock更细粒度控制的场景
- 需要Condition支持的写锁场景
- 缓存系统、数据库访问等读多写少的应用
注意事项:
- 必须在finally块中释放锁
- 避免读写锁嵌套导致死锁
- 合理选择公平性策略
- 正确处理中断异常
- 监控锁的使用情况
- 避免长时间持有锁
- 注意读写锁的语义区别
性能优化建议:
- 根据读写比例选择合适的锁类型
- 合理设置超时时间
- 使用公平锁避免线程饥饿
- 监控锁的竞争情况
- 优化临界区代码减少持有时间
- 考虑使用更细粒度的锁
- 定期分析和调优锁的使用
- 在读多写少的场景下充分发挥读并发优势
JDK 8 Exchanger源码详解与特性分析


被折叠的 条评论
为什么被折叠?



