[重學Java基礎][Java IO流][Part.5]管道字符輸入輸出流

[重學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

概述

源碼分析

Alt text

成員變量

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章