Java中PipedReader与PipedWriter通过内存管道实现线程间同步字符流通信,需先connect连接且读写必须分属不同线程,否则会阻塞或抛异常;默认缓冲区1024字符,适用于简单文本流场景如日志转发。

Java 中可以通过 PipedReader 和 PipedWriter 实现两个线程之间的同步字符流通信,本质是基于内存的管道,无需底层系统管道支持。关键在于:**必须先建立连接(connect),且读写需在不同线程中进行,否则会阻塞或抛出异常。**
一、基本使用流程:配对 + 连接 + 分线程读写
PipedReader 本身不持有数据,它必须与一个 PipedWriter 关联才能工作。典型步骤如下:
- 创建一对管道流:new PipedReader() 和 new PipedWriter()
- 调用
pipedReader.connect(pipedWriter)或pipedWriter.connect(pipedReader)建立连接(二者选一即可) - 在一个线程中向
PipedWriter写入字符(如write("hello")),在另一个线程中从PipedReader读取(如read()或read(char[])) - 注意:若未连接就尝试读/写,会抛出
IOException;若单线程内先写后读,会因缓冲区满或未唤醒而死锁
二、典型示例:生产者-消费者模式
以下是一个安全的双线程通信片段:
PipedReader reader = new PipedReader();
PipedWriter writer = new PipedWriter();
// 建立连接
reader.connect(writer); // 或 writer.connect(reader)
// 启动读线程(消费者)
new Thread(() -> {
try {
int c;
while ((c = reader.read()) != -1) {
System.out.print((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// 主线程作为写线程(生产者)
try {
writer.write("Hello from pipe!");
writer.close(); // 关闭写端会触发读端返回 -1
} catch (IOException e) {
e.printStackTrace();
}
输出:Hello from pipe!。注意 close() 是通知读端结束的常用方式。
立即学习“Java免费学习笔记(深入)”;
三、注意事项和常见问题
使用管道流时容易忽略的关键点:
-
线程隔离是硬性要求:不能在同一个线程里既写又读,否则极易阻塞(例如写满内部缓冲区 1024 字节后,
write()会等待读线程消费) - 缓冲区大小固定:默认为 1024 字符,不可配置;若写入量大且读取慢,会阻塞写操作
-
异常处理要到位:任一线程异常退出未关闭流,另一端可能永远阻塞;建议配合
try-with-resources或 finally 块确保关闭 -
不适用于高吞吐或复杂协议:它是简单字符流,无消息边界、无类型支持;如需结构化通信,应考虑
BlockingQueue、Exchanger或 NIO 管道
四、替代方案对比(何时不该用管道流)
虽然 PipedReader/PipedWriter 能实现线程通信,但多数场景有更优选择:
- 传递对象?→ 用
BlockingQueue<Object>(如LinkedBlockingQueue) - 双向交换数据?→ 用
Exchanger<T> - 需要字节级控制或非阻塞?→ 用 NIO 的
Pipe(返回SelectableChannel) - 只是简单通知?→
wait()/notify()或CountDownLatch更轻量
管道流适合“一个线程持续生成文本流、另一个线程逐字符/块消费”的特定场景,比如模拟终端输入输出、日志转发等。


















