管道流用于线程间单向字节流传输,需成对绑定、分线程读写,缓冲区控制阻塞行为,关闭后读端返回-1,适用于轻量低延迟一对一场景。

管道流(PipedInputStream / PipedOutputStream)不是用来传“变量”的,而是在线程间传递**字节流数据**——它不传输 Java 对象、引用或变量本身,只传输原始字节。所谓“数据变量传输”是误读;实际是:一个线程把字节写入 PipedOutputStream,另一个线程从关联的 PipedInputStream 读出这些字节,完成内存级、单向、同步的数据搬运。
必须成对绑定,且严格分线程操作
两个流必须构成封闭管道:
- 推荐用构造函数直接绑定:
new PipedInputStream(pos)或new PipedOutputStream(pis),避免竞态导致 Pipe not connected - 绝对不可在同一线程中既 write 又 read —— 会立即死锁:写端等读消费,读端等写入,双方无限等待
- 读写必须分离到不同线程:写线程专责
write(),读线程专责read(),不能交叉或复用
阻塞机制与缓冲区控制是关键
默认 1024 字节缓冲区决定了行为边界:
- 写端调用
write()时,若缓冲区已满,线程阻塞,直到读端取走部分数据 - 读端调用
read()时,若缓冲区为空,线程阻塞,直到写端填入新字节 - 可显式指定缓冲大小(如
new PipedInputStream(8)),小缓冲能降低延迟,但不能设为 0 - 避免逐字节写(
write(int b)):频繁加锁唤醒开销大;改用write(byte[], off, len)批量写更高效
生命周期管理:结束信号靠返回值,不靠异常
写端关闭不是“抛异常通知”,而是让读端感知 EOF:
- 写线程调用
pos.close()后,读端下一次read()立即返回 -1,表示流正常结束 -
read()不会自动抛异常,也不会触发 try-with-resources 的 close;必须手动检查if (b == -1) break; - 若需区分“主动关闭”和“崩溃中断”,可在 close 前写一个特殊标记字节(如
pos.write(-2)),读端收到即按错误路径处理 - 读端检测到 -1 后,应主动调用
pis.close()释放资源,不能依赖自动回收
适用场景与替代提醒
它适合轻量、低延迟、单向、一对一的字节流转发:
- 典型用例:日志生成线程 → 日志解析线程;传感器采样线程 → 数据聚合线程
- 不支持多生产者/多消费者:并发写入会触发 Write end dead
- 不支持 NIO 异步操作,无法注册到 Selector,也不能被 Netty 直接封装
- 常规生产者-消费者逻辑,仍应优先选
BlockingQueue—— 更健壮、有超时、支持对象、可扩容











