PipedInputSream/PipedOutputStream
首先:這兩個類就是爲了在線程之間傳輸數據,通過使用這兩個類來實現各個程序模塊之間的鬆耦合通信。
一個PipedInputStream應該只一個PipedOutputStream 綁定,不然可能造成狀態混亂的。
關於其內部源碼的實現:
內部默認緩存數組大小1024
PipedInputSream/PipedOutputStream這套機制的總體思想是阻塞的讀、寫緩存數組,這個緩存數組是PipedInputStream的成員變量。若數組爲空則Input阻塞等到緩存數組有數據寫入,若數組滿了則Output阻塞等到數組有空餘。
PipedOutputStream的write()內部其實是調用的PipedInputStream的receive()方法,且該方法是synchronized 修飾的。receive方法內部當緩存數組寫滿是,就會調用wait(1000)阻塞住調用PipedOutputStream的write線程,直到緩存數組可寫。
而當調用PipedInputStream的read()方法時,如果緩存數組爲空,read()方法內部也會調用wait(1000)阻塞當前的read線程,直到緩存數組中有數據寫入
舉個栗子:
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Arrays;
class Producer extends Thread {
PipedOutputStream outputStream;
public Producer(PipedInputStream inputStream) throws IOException {
this.outputStream = new PipedOutputStream(inputStream);
}
private void produce() throws IOException {
byte[] data1 = "Hello Consumer.我是生產者".getBytes();
System.out.println("data1 len=" + data1.length);
System.out.println("data2 len=10240");
byte[] data2 = new byte[1024 * 10];
for (int i = 0; i < 1024 * 10; i++) {
data2[i] = 3;
}
this.outputStream.write(data1);
System.out.println("producer wrote data1");
this.outputStream.write(data2);
System.out.println("producer wrote data2");
outputStream.close();
/**
這裏要記得關閉輸出流。這個close被override了,這個函數內部是調用了PipedInputStream中的receivedLast函數,其會設置PipedInputStream的成員變量closedByWriter 爲true,從而下次read的時候返回-1
如果沒有關閉的話,producer線程直接退出,會導致consumer在read的時候拋錯:java.io.IOException: Write end dead。
receivedLast源碼,JDK1.7
synchronized void receivedLast() {
closedByWriter = true;
notifyAll();//通知還在阻塞等待的read線程或write線程。
}
**/
}
@Override
public void run() {
try {
produce();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Consumer extends Thread {
PipedInputStream inputStream = new PipedInputStream();
private void consume() throws IOException {
byte[] buf = new byte[2048];
int offset = this.inputStream.read(buf);
System.out.println("consumer read data1:" + new String(Arrays.copyOfRange(buf, 0, 15 + 5 * 3)));//不指定編碼的話,將採用系統默認編碼。本機默認編碼是UTF-8。因此因此英文佔1字節,中文佔3字節
int data2Len = offset - 30;
while (offset != -1) {
offset = this.inputStream.read(buf);
if (offset != -1) data2Len += offset;
}
System.out.println("consumer read data2 len:" + data2Len);
inputStream.close();
}
public PipedInputStream getInputStream() {
return inputStream;
}
@Override
public void run() {
try {
consume();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class PipedStream {
public static void main(String[] args) throws IOException {
String defaultCharsetName = Charset.defaultCharset().displayName();
System.out.println("defaultCharsetName:" + defaultCharsetName);//獲取默認編碼字符
Consumer consumer = new Consumer();
Producer producer = new Producer(consumer.getInputStream());
consumer.start();
producer.start();
}
}