Java管道流(PipedInputStream/PipedOutputStream)通过内存缓冲区实现双线程字节通信,需成对连接、注意启动顺序与异常处理,现代开发更推荐BlockingQueue、Exchanger等并发工具替代。

Java 中的管道流(PipedInputStream 和 PipedOutputStream)可用于两个线程之间的直接字节流通信,本质是通过内存缓冲区实现“一个线程写、另一个线程读”的同步协作。它不依赖外部资源,轻量但需注意线程启动顺序和异常处理。
核心机制:绑定输入与输出流
管道流必须成对使用,并通过 connect() 方法或构造函数建立连接。未连接的管道流无法工作,否则会抛出 IOException。
- 创建 PipedOutputStream 实例后,可传入 PipedInputStream 构造器完成绑定:new PipedInputStream(pipedOutputStream)
- 或调用 pipedReader.connect(pipedWriter)(注意:方法名是 connect,参数是对方流)
- 一旦连接,两个流共享同一内部缓冲区(默认大小 1024 字节),写入端阻塞直到读取端消费数据,反之亦然
典型使用模式:生产者-消费者线程模型
一个线程向 PipedOutputStream 写数据,另一个线程从关联的 PipedInputStream 读数据。必须确保读线程先启动(或至少已进入 read() 阻塞),否则写线程首次 write 可能因缓冲区满且无人读而永久阻塞。
- 推荐在启动写线程前,先启动读线程并让它进入阻塞读状态(如调用 read())
- 读写双方都应捕获 IOException —— 例如读线程关闭流时,写线程继续 write 会触发异常
- 示例场景:主线程生成日志字符串 → 写入 PipedOutputStream;子线程从 PipedInputStream 读取并异步打印
注意事项与常见陷阱
管道流不是万能线程通信方案,适用场景有限,误用易导致死锁或异常。
立即学习“Java免费学习笔记(深入)”;
- 不能跨线程复用流:PipedInputStream 必须由单一线程读取,PipedOutputStream 必须由单一线程写入,否则行为未定义
- 不支持多对一或一对多:一个 PipedOutputStream 只能 connect 一个 PipedInputStream,反之亦然
- 异常传播敏感:任一端流 close(),另一端再操作会立即抛出 IOException,需做好 try-catch + 资源清理
- 若需更灵活通信(如对象传递、多线程安全、背压控制),优先考虑 BlockingQueue、Exchanger 或 java.util.concurrent 包中的工具类
替代建议:现代 Java 更推荐的方式
管道流属于较老的 IO 设计,JDK 5+ 后基本被更高层并发工具取代:
- 传输字节/文本:用 BlockingQueue
或 SynchronousQueue - 传递对象:用 BlockingQueue
(配合 Serializable 或自定义序列化) - 双向交换:用 Exchanger
让两个线程在指定点交换数据 - 响应式流:在复杂异步场景中,可考虑 Project Reactor 或 RxJava 的 Flux/Mono


















