Java PipedReader 类
最后修改时间:2025 年 4 月 16 日
java.io.PipedReader 类是一个字符流,从管道中读取数据。它必须连接到 PipedWriter 才能形成管道。写入到 PipedWriter 的数据可以从 PipedReader 中读取。
PipedReader 通常用于线程之间的通信。管道提供了一种线程向另一个线程发送数据的方式。管道有一个固定大小的缓冲区,当缓冲区满或空时,操作会阻塞。
PipedReader 类概述
PipedReader 继承自 Reader,并提供基于字符的管道读取功能。关键方法包括读取操作和连接管理。该类对于多个读取器的并发访问不是线程安全的。
public class PipedReader extends Reader {
public PipedReader();
public PipedReader(int pipeSize);
public PipedReader(PipedWriter src);
public PipedReader(PipedWriter src, int pipeSize);
public void connect(PipedWriter src);
public synchronized int read();
public synchronized int read(char[] cbuf, int off, int len);
public synchronized void close();
}
上面的代码显示了 PipedReader 提供的关键方法。这些方法允许从连接到 PipedWriter 的管道中读取字符。可以指定管道大小或使用默认值(1024 个字符)。
创建 PipedReader
可以以多种方式创建 PipedReader。您可以创建一个未连接的读取器,稍后连接它,或者创建它时已经连接到写入器。管道大小会影响线程之间可以缓冲的数据量。
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// Create unconnected PipedReader
PipedReader reader1 = new PipedReader();
// Create with default pipe size (1024)
PipedWriter writer1 = new PipedWriter();
PipedReader reader2 = new PipedReader(writer1);
// Create with custom pipe size (2048)
PipedWriter writer2 = new PipedWriter();
PipedReader reader3 = new PipedReader(writer2, 2048);
System.out.println("Created three PipedReader instances");
reader1.close();
reader2.close();
reader3.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例演示了创建 PipedReader 的不同方法。第一个创建了一个未连接的读取器。第二个和第三个创建了连接的读取器,分别使用默认和自定义管道大小。完成操作后,请务必关闭读取器以释放资源。
PipedReader 的基本用法
使用 PipedReader 的最简单方法是将其连接到 PipedWriter 并读取字符。当没有数据可用时,读取操作会阻塞。这对于线程通信很有用。
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader(writer);
// Write data in a separate thread
new Thread(() -> {
try {
writer.write("Hello from PipedWriter!");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// Read data from the pipe
int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}
System.out.println("\nReading complete");
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例显示了线程之间的基本管道通信。写入器线程发送数据,主线程读取数据。read 方法会阻塞,直到有数据可用。当写入器关闭时,管道会自动关闭。
将字符读取到数组中
为了获得更好的性能,一次将多个字符读入一个 char 数组。 这减少了方法调用并提高了效率。 read 方法返回实际读取的字符数。
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader(writer, 4096); // 4KB buffer
// Writer thread
new Thread(() -> {
try {
String message = "This is a longer message demonstrating " +
"bulk reading from a PipedReader. " +
"Reading multiple characters at once is more efficient.";
writer.write(message);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// Reader with buffer
char[] buffer = new char[32];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, charsRead));
}
System.out.println("\nBulk reading complete");
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例演示了批量读取到字符数组中。管道具有 4KB 的缓冲区大小。读取器一次处理 32 个字符。charsRead 值指示实际读取到数组中的字符数。
稍后连接 PipedReader
PipedReader 可以在创建时未连接,稍后连接到写入器。必须在进行任何读写操作之前建立连接。尝试使用未连接的管道会导致 IOException。
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// Create unconnected reader
PipedReader reader = new PipedReader();
// Create writer and connect later
PipedWriter writer = new PipedWriter();
// Connect them (can also use writer.connect(reader))
reader.connect(writer);
// Write data in a separate thread
new Thread(() -> {
try {
writer.write("Connected after creation");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// Read data
int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}
System.out.println("\nReading from late-connected pipe complete");
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例显示了如何在创建后连接 PipedReader。连接可以从任何一端进行。连接后,管道的工作方式与创建时已连接的方式相同。一次只能存在一个连接。
处理管道缓冲区已满的情况
当管道缓冲区已满时,写入操作会阻塞,直到有空间可用。类似地,当缓冲区为空时,读取操作会阻塞。此行为对于正确的线程协调非常重要。
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// Small pipe buffer (10 chars)
PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader(writer, 10);
// Writer thread that writes more than buffer can hold
Thread writerThread = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
writer.write('A' + (i % 26));
System.out.println("Wrote: " + (char)('A' + (i % 26)));
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
});
// Slow reader thread
Thread readerThread = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
Thread.sleep(200); // Slow reading
char c = (char) reader.read();
System.out.println("Read: " + c);
}
} catch (Exception e) {
e.printStackTrace();
}
});
writerThread.start();
readerThread.start();
writerThread.join();
readerThread.join();
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
此示例演示了管道阻塞行为。当 10 个字符的缓冲区已满时,写入器将阻塞。缓慢的读取器逐渐消耗数据,允许写入器继续。这展示了管道如何自然地同步生产者和消费者线程。
来源
在本文中,我们介绍了 Java PipedReader 类的基本方法和特性。理解这些概念对于在 Java 应用程序中使用字符流实现线程间通信至关重要。
作者
列出所有Java教程。