在Java的IO流体系中,PipedReader和PipedWriter是用于线程间字符通讯的一对管道流,它们可以在两个运行中的本地线程之间传递字符数据,不需要借助额外的共享变量或者外部存储。

PipedReader和PipedWriter的核心特性
PipedReader是字符管道输入流,用于读取管道中的字符数据;PipedWriter是字符管道输出流,用于向管道中写入字符数据。两者需要配对使用,通常一个线程作为写入方,另一个线程作为读取方,通过管道建立连接后就可以实现数据的单向传递。
需要注意的是,这两个流本身没有线程安全的保证,因此一般建议一个PipedWriter只对应一个写入线程,一个PipedReader只对应一个读取线程,避免多线程操作同一个流导致数据混乱。
建立管道连接的两种方式
使用PipedReader和PipedWriter实现通讯,首先需要建立两者的连接,有两种常用的连接方式:
方式一:通过构造方法连接
可以在创建PipedReader的时候,直接传入PipedWriter对象完成连接,示例代码如下:
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class PipeConnectDemo1 {
public static void main(String[] args) throws IOException {
// 创建管道输出流
PipedWriter writer = new PipedWriter();
// 创建管道输入流,并和输出流绑定
PipedReader reader = new PipedReader(writer);
System.out.println("管道连接成功");
}
}
方式二:通过connect方法连接
也可以先分别创建两个流对象,之后调用PipedReader或者PipedWriter的connect方法建立连接,示例代码如下:
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class PipeConnectDemo2 {
public static void main(String[] args) throws IOException {
PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader();
// 调用connect方法建立连接
writer.connect(reader);
// 也可以写成 reader.connect(writer),效果一致
System.out.println("管道连接成功");
}
}
完整的线程间字符通讯示例
下面通过一个完整的示例,展示两个本地线程如何通过PipedReader和PipedWriter实现字符通讯:一个线程负责写入字符串数据,另一个线程负责读取并打印数据。
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class ThreadCharCommunicate {
public static void main(String[] args) {
try {
// 创建管道输出流和输入流
PipedWriter pipedWriter = new PipedWriter();
PipedReader pipedReader = new PipedReader();
// 建立连接
pipedWriter.connect(pipedReader);
// 创建写入线程,负责向管道写入字符数据
Thread writeThread = new Thread(() -> {
try {
String message = "这是来自写入线程的字符消息";
System.out.println("写入线程开始写入数据:" + message);
// 写入字符数据
pipedWriter.write(message);
// 写入完成后关闭流
pipedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}, "write-thread");
// 创建读取线程,负责从管道读取字符数据
Thread readThread = new Thread(() -> {
try {
// 用于临时存储读取的字符
StringBuilder result = new StringBuilder();
int readChar;
// 循环读取管道中的字符,read方法返回-1表示流结束
while ((readChar = pipedReader.read()) != -1) {
result.append((char) readChar);
}
System.out.println("读取线程接收到数据:" + result.toString());
// 读取完成后关闭流
pipedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}, "read-thread");
// 启动两个线程
writeThread.start();
readThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行上述代码,输出结果如下:
写入线程开始写入数据:这是来自写入线程的字符消息 读取线程接收到数据:这是来自写入线程的字符消息
使用注意事项
- 管道流的连接必须在读写操作之前完成,否则会抛出IOException异常。
- 写入线程写入数据后,如果没有关闭输出流,读取线程的read方法会一直阻塞等待新数据,因此写入完成后需要及时关闭流,或者在写入结束标记让读取线程知道数据已经传输完毕。
- 如果读取线程先启动,在没有数据可读的时候,read方法会进入阻塞状态,直到有数据写入或者流被关闭。
- 不要对同一个管道流进行双向读写,PipedReader和PipedWriter是单向传输设计,双向通讯需要创建两对管道流分别处理两个方向的数据。
- 如果需要在多个线程之间传递对象数据,不建议使用字符管道流,更适合使用ObjectOutputStream和ObjectInputStream配合PipedOutputStream、PipedInputStream实现。
常见问题解答
为什么读取线程会阻塞?
当管道中没有数据可读,且对应的PipedWriter没有关闭时,PipedReader的read方法会一直阻塞,直到有新的数据写入或者流被关闭。这是正常的阻塞特性,不需要额外处理,只需要在写入完成后正确关闭流即可。
可以多个线程同时写入同一个PipedWriter吗?
不建议这样做,PipedWriter本身不是线程安全的,多个线程同时写入可能会导致数据错乱,如果需要多个线程写入,需要自己添加同步锁保证同一时间只有一个线程执行写入操作。
PipedReaderPipedWriterJava线程通讯修改时间:2026-07-13 19:03:27