管道流(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();
}
}
重點
- 如果不創建某種類型的讀取器并連接到它,就無法寫入管道。換言之,兩端必須存在并已經連接,以便寫入結束工作。
- 當您完成對管道的寫入時,您不能切換到另一個管道(未連接的讀取器)。
- 如果關閉讀取器,則無法從管道讀取。然而,您可以成功地關閉寫入結束,并且仍然從管道讀取。
- 如果寫入線程的線程結束,則無法從管道中讀取。