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教程。