pipe通过sinkchannel和sourcechannel实现nio线程间单向无锁传输:写线程非阻塞写入,读线程selector监听读就绪后读取,两端关闭任一即整管失效,需协调生命周期。

通过 Pipe 在两个 NIO 线程间实现单向数据传输,本质是利用 Java NIO 提供的线程安全、无锁的管道机制:一个线程写入 Pipe.SinkChannel,另一个线程从 Pipe.SourceChannel 读取。它天然适合单向、生产者-消费者模型,且不依赖外部同步。
创建并理解 Pipe 的两端
Pipe pipe = Pipe.open(); 会同时创建一对关联的通道:
– Pipe.SinkChannel:只写通道,类似“入口”,支持非阻塞写(需配置为 configureBlocking(false));
– Pipe.SourceChannel:只读通道,类似“出口”,也支持非阻塞读。
两者绑定在同一内核管道上,数据写入 Sink 后可立即被 Source 读到,无需缓冲区管理或序列化。
写线程:向 SinkChannel 写入数据
写线程通常配合 Selector 或直接轮询,注意以下要点:
- 调用
sinkChannel.write(ByteBuffer),返回实际写入字节数;若为 0 且通道是非阻塞的,说明暂时不可写(如内核缓冲区满),应稍后重试 - 务必检查
write()返回值,避免假定全部写入;必要时循环写或切分 buffer - 写完后可调用
buffer.clear()或buffer.compact()复用 buffer
读线程:从 SourceChannel 读取数据
读线程推荐使用 Selector 监听 SelectionKey.OP_READ 事件,提高效率:
- 注册前确保
sourceChannel.configureBlocking(false) - 收到读就绪通知后,调用
sourceChannel.read(ByteBuffer);返回 -1 表示管道已关闭,0 表示暂无数据(非错误) - 读取后用
buffer.flip()切换至读模式,处理有效数据;再buffer.clear()准备下次读
线程安全与关闭注意事项
Pipe 本身线程安全,但需注意生命周期协调:
- 任意一端关闭(
close()),整条管道即失效,另一端后续 I/O 将抛ClosedChannelException - 不要在写线程中关闭
SinkChannel后还尝试写入;也不应在读线程中关闭SourceChannel后继续注册 selector - 若需优雅终止,可约定特殊消息(如空 buffer 或特定字节序列),或借助额外标志位 +
selector.wakeup()










