# Java 线程间通信 – `PipedReader`和`PipedWriter`

> 原文： [https://howtodoinjava.com/java/multi-threading/inter-thread-communication-using-piped-streams-in-java/](https://howtodoinjava.com/java/multi-threading/inter-thread-communication-using-piped-streams-in-java/)

Java 线程间通信在很长一段时间以来一直是热门的[面试问题](https://howtodoinjava.com/java-interview-questions/)。 在 JDK 1.5 版本中，[`ExecutorService`](https://howtodoinjava.com/java/multi-threading/java-executor-framework-tutorial-and-best-practices/)和[`BlockingQueue`](https://howtodoinjava.com/java/multi-threading/how-to-use-blockingqueue-and-threadpoolexecutor-in-java/)[带来了另一种更有效的实现方式](//howtodoinjava.com/java-5/how-to-use-blockingqueue-and-threadpoolexecutor-in-java/ "How to use BlockingQueue and ThreadPoolExecutor in java")，但管道流方法也值得了解，在某些情况下可能有用。

```java
Table of contents

What are piped streams
PipedReader and PipedWriter
Java inter-thread communication example
Summary
```

## 什么是管道流

**管道流**就像真实的管道一样。 您可以使用某些方法将事物一端放入管道中。 然后，您可以使用其他方法从另一端的管道流中收到相同的信息。

它们以 [**FIFO 顺序**](https://en.wikipedia.org/wiki/FIFO "fifo")的先入先出的方式出现，就像从实际的管道中一样。

## `PipedReader`和`PipedWriter`

[**`PipedReader`**](https://docs.oracle.com/javase/7/docs/api/java/io/PipedReader.html)是[**`Reader`**](https://docs.oracle.com/javase/7/docs/api/java/io/Reader.html "Reader")类的扩展，用于读取字符流。 它的`read()`方法读取连接的`PipedWriter`的流。 同样，[**`PipedWriter`**](https://docs.oracle.com/javase/7/docs/api/java/io/PipedWriter.html) 是`Writer`类的扩展，它执行`Reader`类所收缩的所有工作。

可以通过以下两种方法将作家连接到读者：

1.  使用构造器`PipedWriter(PipedReader pr)`
2.  使用`connect(PipedReader pr)`方法

通过上述任何一种方式连接后，任何线程都可以使用`write(....)`方法在流中写入数据，并且数据将可供读取器使用，并且可以使用`read()`方法进行读取。

## Java 线程间通信示例

下面给出的 Java 程序创建两个线程。 一个线程负责写入流，第二个线程仅读取数据以在控制台中打印它们。

```java
public class PipeReaderThread implements Runnable 
{
    PipedReader pr;
    String name = null;

	public PipeReaderThread(String name, PipedReader pr) 
	{
	    this.name = name;
	    this.pr = pr;
	}

	public void run() 
	{
	    try {
	        // continuously read data from stream and print it in console
	        while (true) {
	            char c = (char) pr.read(); // read a char
	            if (c != -1) { // check for -1 indicating end of file
	                System.out.print(c);
	            }
	        }
	    } catch (Exception e) {
	        System.out.println(" PipeThread Exception: " + e);
	    }
	}
}

```

```java
public class PipeWriterThread implements Runnable 
{
    PipedWriter pw;
    String name = null;

	public PipeWriterThread(String name, PipedWriter pw) {
	    this.name = name;
	    this.pw = pw;
	}

	public void run() {
	    try {
	        while (true) {
	            // Write some data after every two seconds
	            pw.write("Testing data written...n");
	            pw.flush();
	            Thread.sleep(2000);
	        }
	    } catch (Exception e) {
	        System.out.println(" PipeThread Exception: " + e);
	    }
	}
}

```

```java
package multiThread;

import java.io.*;

public class PipedCommunicationTest 
{
	public static void main(String[] args) 
	{
	    new PipedCommunicationTest();
	}

	public PipedCommunicationTest() 
	{
	    try 
	    {
	        // Create writer and reader instances
	        PipedReader pr = new PipedReader();
	        PipedWriter pw = new PipedWriter();

	        // Connect the writer with reader
	        pw.connect(pr);

	        // Create one writer thread and one reader thread
	        Thread thread1 = new Thread(new PipeReaderThread("ReaderThread", pr));

	        Thread thread2 = new Thread(new PipeWriterThread("WriterThread", pw));

	        // start both threads
	        thread1.start();
	        thread2.start();

	    } 
	    catch (Exception e) 
	    {
	        System.out.println("PipeThread Exception: " + e);
	    }
	}
}

```

程序输出：

```java
Testing data written...
Testing data written...
Testing data written...

```

## 总结

*   您必须先创建某种类型的读取器并将其连接，然后才能写入管道。 换句话说，两个端必须存在并且已经连接，以使写入端正常工作。
*   完成写入管道后，您将无法切换到最初未连接管道的其他读取器。
*   如果关闭阅读器，则无法从管道中读回。 但是，您可以成功关闭写入端，并且仍然可以从管道读取数据。
*   如果写入管道的线程结束，则无法从管道读回。

学习愉快！