java管道流专为同进程线程间高效通信设计,依赖显式connect()连接、环形缓冲区背压机制及正确close()释放资源,须区分字节流与字符流并避免混用。

必须先连接,再启线程
管道流不是即插即用的——PipedInputStream 和 PipedOutputStream(或 PipedReader/PipedWriter)必须显式调用 connect() 方法绑定,否则运行时抛出 IOException: Pipe not connected。连接操作可在任意线程执行,但务必在任一线程开始读/写前完成。
- 推荐在主线程中创建并连接:先 new 两个流,立刻调用
input.connect(output) - 不要在读线程里 connect 输入流,也不要在写线程里 connect 输出流——容易因时序错乱导致阻塞或异常
- 字符流与字节流不能混用:PipedReader 只能连 PipedWriter,PipedInputStream 只能连 PipedOutputStream
用环形缓冲区控制吞吐,避免死锁
Java管道底层是固定大小(默认1024字节)的环形缓冲区。当写入方填满缓冲区,write() 会自动阻塞;当读取方读空缓冲区,read() 同样阻塞。这种天然的“背压”机制省去了手动信号协调,但需注意:
- 写入大块数据前,建议分批写(如每次 ≤512字节),防止单次 write 长时间阻塞影响响应
- 读取端应循环调用
read()直到返回 -1(流关闭),不要只读一次就退出 - 务必在读写完成后调用
close():关闭输出流会触发输入流的 EOF,是通知消费者结束的标准方式
按场景选字节流还是字符流
传输原始二进制数据(如图片字节数组、序列化对象)用 PipedInputStream / PipedOutputStream;处理文本、日志、协议消息等字符串内容,优先选 PipedReader / PipedWriter,可直接写入/读取 char 或 String,无需手动编码解码。
- 字符流对中文等 Unicode 支持更自然,避免 getBytes() 编码不一致引发乱码
- 若需带换行分隔的消息(如命令行协议),用 PipedReader 逐行读
readLine()更简洁 - 字节流更通用,但处理文本时需统一约定字符集(如 UTF-8),并在 write 前明确调用
string.getBytes(StandardCharsets.UTF_8)
配合 try-with-resources 确保资源释放
管道流属于 I/O 资源,未关闭可能造成内存泄漏或线程永久阻塞。Java 7+ 推荐使用 try-with-resources 自动管理:
try (PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream()) {
in.connect(out);
// 启动读写线程...
} // 自动 close,无论是否异常
- 即使线程中发生异常,close() 仍会被调用,保障输入流能及时感知 EOF
- 避免在 run() 方法里仅用 finally 手动 close —— 若线程被 interrupt,可能跳过 finally
- 多个线程共用同一管道时,确保只有一个写入方和一个读取方,多写或多读会导致 IOException
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











