pipedinputstream 和 pipedoutputstream 是 java 中专用于线程间通信的内存管道流,必须配对使用且需先 connect 再启动线程;写入阻塞于缓冲区满(默认1024字节),读取阻塞于缓冲区空,写线程关闭输出流后读线程 read() 返回-1 表示结束。

PipedInputStream 和 PipedOutputStream 是 Java IO 包中专为线程间通信设计的一对管道流。它们不操作文件或网络,而是让一个线程写入数据、另一个线程同步读取,底层通过内存缓冲区实现“管道”效果。关键在于:二者必须配对使用,且需在启动读/写线程前完成连接。
必须先连接,再启线程
不能先启动写线程再连接,否则写入时会抛 IOException: Pipe not connected。正确做法是创建两个流后立即调用 connect(),或用构造函数直接关联:
- 方式一(显式连接):
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pis.connect(pos); // 必须在这一步完成 - 方式二(构造时连接):
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream(pis); // 自动连接
读写线程分工明确,避免阻塞死锁
写线程用 PipedOutputStream.write() 写入,读线程用 PipedInputStream.read() 读取。注意:当缓冲区满(默认 1024 字节),写操作会阻塞;当缓冲区空,读操作会阻塞。因此必须确保两端都有线程在运行,否则会卡住。
- 读线程应持续调用
read()或read(byte[]),不要只读一次就退出 - 写线程写完后建议调用
pos.close(),这样读线程的read()会返回 -1,表示流结束 - 若不关闭,读线程可能永远等待新数据
实际使用示例(字符串传递)
以下是一个完整可运行的小例子,主线程向子线程发送字符串,子线程读取并打印:
- 创建管道流并连接
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in); - 启动读线程(处理输入)
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(in))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("收到:" + line);
}
} catch (IOException e) { e.printStackTrace(); }
}).start(); - 主线程写入并关闭
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(out))) {
writer.write("Hello from main thread");
writer.newLine();
writer.flush();
} // close() 触发读端 read() 返回 -1
注意事项与替代建议
虽然 PipedInputStream 能实现线程通信,但它属于阻塞式 IO,且容易因连接顺序或关闭时机出错。现代开发中更推荐:
- 用
BlockingQueue(如LinkedBlockingQueue)传递对象,类型安全、无需手动处理字节流 - 用
Exchanger实现双向数据交换 - 若需流式处理且强调响应性,可考虑
java.util.concurrent.Flow(JDK 9+ 的 Reactive Streams 支持)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











