[重學Java基礎][JavaIO流][Part.5]管道字符輸入輸出流
PipedReader
概述
PipedReader管道輸入流 需要配合管道輸出流PipedWriter使用 用於線程間通訊
在線程間開啓一個管道 互相傳輸數據
源碼分析
成員變量
PipedWriter對象是否關閉
boolean closedByWriter = false;
PipedReader對象是否關閉
boolean closedByReader = false;
連接是否關閉
boolean connected = false;
進行讀入的線程
Thread readSide;
進行寫出的線程
Thread writeSide;
默認的緩衝字符數組大小
private static final int DEFAULT_PIPE_SIZE = 1024;
緩衝字符數組
char buffer[];
下一個從管道讀入到緩衝數組的字符遊標位置 如果in==out說明已經讀入完畢
int in = -1;
int out = 0;
成員方法
構造函數 可以自主制定管道緩衝大小或者使用默認值 指定與PipedReader相連的PipedWriter 對象
public PipedReader() {
initPipe(DEFAULT_PIPE_SIZE);
}
public PipedReader(int pipeSize) {
initPipe(pipeSize);
}
public PipedReader(PipedWriter src) throws IOException {
this(src, DEFAULT_PIPE_SIZE);
}
public PipedReader(PipedWriter src, int pipeSize) throws IOException {
initPipe(pipeSize);
connect(src);
}
連接 實際上調用的是PipedWriter 對象的connect()方法
public void connect(PipedWriter src) throws IOException {
src.connect(this);
}
接收方法
接收字符數據 只會在PipedWriter的write(int b)中會被調用
synchronized void receive(int c) throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByWriter || closedByReader) {
throw new IOException("Pipe closed");
} else if (readSide != null && !readSide.isAlive()) {
throw new IOException("Read end dead");
}
writeSide = Thread.currentThread();
每隔1s檢查“管道狀態”,並喚醒管道操作
若有“讀取管道數據線程被阻塞”,則喚醒該線程
直到數據被全部讀取(in==out)
while (in == out) {
if ((readSide != null) && !readSide.isAlive()) {
throw new IOException("Pipe broken");
}
notifyAll();
try {
wait(1000);
} catch (InterruptedException ex) {
throw new java.io.InterruptedIOException();
}
}
if (in < 0) {
in = 0;
out = 0;
}
buffer[in++] = (char) c;
if (in >= buffer.length) {
in = 0;
}
}
按字符讀入 並制定起始位置和讀入長度
synchronized void receive(char c[], int off, int len) throws IOException {
while (--len >= 0) {
receive(c[off++]);
}
}
接受完畢 通知所有線程此管道被關閉
synchronized void receivedLast() {
closedByWriter = true;
notifyAll();
}
讀取方法和其他字符輸入流讀取類似 內容省略
PipedWriter
概述
源碼分析
成員變量
PipedReader對象用於和PipedWriter通信
private PipedReader sink;
PipedWriter的關閉標記
private boolean closed = false;
成員方法
構造方法 可以指定連接的PipedReader 對象或者稍後指定
public PipedWriter(PipedReader snk) throws IOException {
connect(snk);
}
public PipedWriter() {
}
連接方法 將此字符輸出管道連接到輸入管道上
public synchronized void connect(PipedReader snk) throws IOException {
檢查連接設置
if (snk == null) {
throw new NullPointerException();
} else if (sink != null || snk.connected) {
throw new IOException("Already connected");
} else if (snk.closedByReader || closed) {
throw new IOException("Pipe closed");
}
sink = snk;
snk.in = -1;
snk.out = 0;
設置Reader對象的連接狀態爲成功
snk.connected = true;
}
刷新管道方法 調用了PipedReader sink的notifyAll()方法 使當前的PipedReader 放棄對資源的佔用 喚醒其他被阻塞的PipedReader 讀取PipedWriter的值
public synchronized void flush() throws IOException {
if (sink != null) {
if (sink.closedByReader || closed) {
throw new IOException("Pipe closed");
}
synchronized (sink) {
sink.notifyAll();
}
}
}
寫入方法 實際上是調用了PipedReader sink的接收方法
public void write(int c) throws IOException {
if (sink == null) {
throw new IOException("Pipe not connected");
}
sink.receive(c);
}
public void write(char cbuf[], int off, int len) throws IOException {
if (sink == null) {
throw new IOException("Pipe not connected");
} else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException();
}
sink.receive(cbuf, off, len);
}
PipedReader PipedWriter綜合代碼示例
發送端
class Sender extends Thread {
//發送端端設置一個內部類PipedWriter的實例對象out用於發送管道數據
private PipedWriter out = new PipedWriter();
// 獲得“管道輸出流”對象
public PipedWriter getWriter(){
return out;
}
@Override
public void run(){
writeShortMessage();
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Sender Over");
}
// 向“管道輸出流”中寫入數據
private void writeShortMessage() {
String strInfo = "this is message sender" ;
try {
out.write(strInfo.toCharArray());
} catch (IOException e) {
e.printStackTrace();
}
}
}
接收端
class Receiver extends Thread {
//接收端設置一個內部類PipedReader的實例對象in用於接受管道數據
private PipedReader in = new PipedReader();
//獲取這個PipedReader對象 用於從外部設置接收端和發送端的連接
public PipedReader getReader(){
return in;
}
@Override
public void run(){
readMessage() ;
//必須全部讀取完畢才能關閉連接 否則會報錯
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Receiver Over");
}
// 從“管道輸入流”中讀取1次數據 需要自己截斷 因爲寫入端是連續寫入的
public void readMessage(){
char[] buf = new char[23];
try {
in.read(buf);
System.out.println(new String(buf,0,23));
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行主函數
public static void main(String[] args) throws IOException {
Sender sender=new Sender();
Receiver receiver=new Receiver();
sender.getWriter().connect(receiver.getReader());
sender.start();
receiver.start();
}
運行結果
this is message sender
Sender Over
Receiver Over