管道流(Piped Streams)这个话题长期以来一直是一个热门的面试问题。JDK 1.5的发布,ExecutorService和BlockingQueue带来的做法更有效,但这种方法也值得了解的,可能在某些情况下是有用的。
什么是管道流
管道流就像真正的水管道,你用一些方法将东西放在管道的一端,然后在管道的另一端使用其他方法接收相同的内容。它们是以先进先出的顺序出来的,就像是从真正的管道中出来的。
PipedReader和PipedWriter
PipedReader类是继承自Reader类(用于字符流的读取),它的read()方法读取连接的PipedWriter的流。同样的,PipedWriter类是继承Writer类,用于做所有与Reader类连接相关的事情。
PipedWriter可以通过以下2个方法与PipedReader连接:
- 使用构造函数PipedWriter(PipedReader pr)
- 使用connect(PipedReader pr) 方法
通过以上方式,一旦连接,任何线程都可以使用write(…)方法写入数据流和使用read()读取数据。
运行例子
在给定的示例程序下面创建两个线程。一个线程负责写入流,第二个线程只读取数据以在控制台中打印它们。
public class PipedCommunicationTest {
public PipedCommunicationTest() {
try {
PipedReader pr = new PipedReader();
PipedWriter pw = new PipedWriter();
pw.connect(pr);
Thread thread1 = new Thread(
new PipeReaderThread("ReaderThread", pr));
Thread thread2 = new Thread(
new PipeWriterThread("WriterThread", pw));
// start both threads
thread1.start();
thread2.start();
} catch (IOException e) {
e.printStackTrace();
}
}
class PipeReaderThread implements Runnable {
String name = null;
PipedReader pr;
public PipeReaderThread(String name, PipedReader pr) {
this.name = name;
this.pr = pr;
}
@Override
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);
}
}
}
class PipeWriterThread implements Runnable {
String name = null;
PipedWriter pw;
public PipeWriterThread(String name, PipedWriter pw) {
this.name = name;
this.pw = pw;
}
@Override
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);
}
}
}
public static void main(String[] args) {
new PipedCommunicationTest();
}
}
重点
- 如果不创建某种类型的读取器并连接到它,就无法写入管道。换言之,两端必须存在并已经连接,以便写入结束工作。
- 当您完成对管道的写入时,您不能切换到另一个管道(未连接的读取器)。
- 如果关闭读取器,则无法从管道读取。然而,您可以成功地关闭写入结束,并且仍然从管道读取。
- 如果写入线程的线程结束,则无法从管道中读取。