Java管道通信需PipedOutputStream与PipedInputStream显式连接,推荐构造时关联;写端write阻塞于缓冲满,close发送EOF;读端read阻塞于无数据,返回-1表示EOF。

Java 中的管道通信通过 PipedOutputStream 和 PipedInputStream 配合实现线程间字节流数据传输,核心是“一个写、一个读”,二者必须连接才能工作。直接使用时需注意线程安全和连接时机,否则会抛出 IOException(如“Pipe not connected”)。
必须先连接,再启动读写线程
两个管道流必须显式连接(connect()),且通常在启动线程前完成。推荐用构造函数直接关联,更安全:
-
不推荐:先创建独立流再调用
connect(),容易因时序问题失败 -
推荐:用
new PipedInputStream(pipedOutputStream)或new PipedOutputStream(pipedInputStream)构造时自动连接
写入端:用 PipedOutputStream 发送数据
在生产者线程中,将 PipedOutputStream 当作普通输出流使用,调用 write() 或 write(byte[]) 写入字节。注意:
- 写入阻塞:当管道缓冲区满(默认 1024 字节)且读端未及时消费时,
write()会阻塞,直到有空间 - 关闭流会向读端发送 EOF:调用
close()后,读端的read()将返回 -1 - 不要在写完立即 close()——除非确定读端已处理完毕,否则可能丢失最后一批数据
读取端:用 PipedInputStream 接收数据
在消费者线程中,从 PipedInputStream 调用 read() 或 read(byte[]) 获取字节。关键点:
立即学习“Java免费学习笔记(深入)”;
- 读取也阻塞:当管道为空且写端未关闭时,
read()会等待新数据到达 - 检测 EOF:返回 -1 表示写端已关闭,应退出读循环
- 建议用带缓冲的包装(如
BufferedInputStream)提升小数据频繁读取的效率
简单可用示例
以下代码演示一个线程写字符串、另一个线程读并打印:
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream(pis); // 自动连接
Thread writer = new Thread(() -> {
try {
pos.write("Hello, Pipe!".getBytes());
pos.close(); // 发送 EOF
} catch (IOException e) {
e.printStackTrace();
}
});
Thread reader = new Thread(() -> {
try {
int b;
while ((b = pis.read()) != -1) {
System.out.print((char) b);
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
});
writer.start();
reader.start();
不复杂但容易忽略连接和关闭顺序。实际项目中建议封装为工具类或改用更现代的线程通信方式(如 BlockingQueue),除非明确需要字节流语义。


















