Java IO:PipedOutputStream和PipedInputStream使用詳解及源碼分析__java

來源:互聯網
上載者:User
1 使用方法

  PipedOutputStream和PipedInputStream是管道輸出資料流和管道輸入資料流,配合使用可以實現線程間通訊。
  使用管道實現線程間通訊的主要流程如下:建立輸出資料流out和輸入資料流in,將out和in綁定,out中寫入的資料則會同步寫入的in的緩衝區(實際情況是,out中寫入資料就是往in的緩衝區寫資料,out中沒有資料緩衝區)。 1.1 方法介紹

  PipedOutputStream提供的API如下:

//建構函式public PipedOutputStream(PipedInputStream snk);public PipedOutputStream();public synchronized void connect(PipedInputStream snk); //將PipedOutputStream 和 PipedInputSteam綁定public void write(int b); //向output寫入bpublic void write(byte b[], int off, int len); //向output寫入位元組數組bpublic synchronized void flush();//重新整理緩衝區,通知其他input讀取資料public void close();// 關閉PipedOutputStream提供的API如下://建構函式public PipedInputStream(PipedOutputStream src);public PipedInputStream(PipedOutputStream src, int pipeSize);public void connect(PipedOutputStream src); //將PipedOutputStream 和 PipedInputSteam綁定protected synchronized void receive(int b); //向input緩衝區寫入bsynchronized void receive(byte b[], int off, int len); //向input寫入位元組數組bpublic synchronized int read(); //讀取緩衝區下一個位元組public synchronized int read(byte b[], int off, int len) //讀取緩衝區位元組數組到bpublic synchronized int available();// 緩衝區可讀位元組數組的個數public void close(); // 關閉
1.2 使用樣本
/** * 生產者線程 */public class Producer extends Thread {    //輸出資料流    private PipedOutputStream out = new PipedOutputStream();    //構造方法    public Producer(PipedOutputStream out) {        this.out = out;    }    @Override    public void run() {        writeMessage();    }    private void writeMessage() {        StringBuilder sb = new StringBuilder("Hello World!!!");        try {            out.write(sb.toString().getBytes());            out.close();        } catch (IOException e) {            e.printStackTrace();        }    }}/** * 消費線程 */public class Consumer extends Thread {    //輸入資料流, 預設緩衝區大小為1024    private PipedInputStream in = new PipedInputStream();    //構造方法    public Consumer(PipedInputStream in) {        this.in = in;    }    @Override    public void run() {        readMessage();    }    private void readMessage() {        byte [] buf = new byte[1024];        try {            int len = in.read(buf);            System.out.println("緩衝區的內容為: " + new String(buf, 0, len));            in.close();        } catch (IOException e) {            e.printStackTrace();        } finally {        }    }}@org.junit.Testpublic void testPiped() {    /**     * 流程     * 1 建立輸入輸出資料流     * 2 綁定輸入輸出資料流     * 3 向緩衝區寫資料     * 4 讀取緩衝區資料     */    PipedOutputStream out = new PipedOutputStream();    PipedInputStream in = new PipedInputStream();    Producer producer = new Producer(out);    Consumer consumer = new Consumer(in);    try {        out.connect(in);        producer.start();        consumer.start();    } catch (IOException e) {        e.printStackTrace();    }}

  運行結果如下:

緩衝區的內容為: Hello World!!!
2 源碼分析

  按照示範程式運行過程分析源碼,主要有構造方法、connect、out寫、in讀等。 2.1 PipedOutputStream構造方法

/** * Creates a piped output stream connected to the specified piped * input stream. Data bytes written to this stream will then be * available as input from <code>snk</code>. * * @param      snk   The piped input stream to connect to. * @exception  IOException  if an I/O error occurs. */public PipedOutputStream(PipedInputStream snk)  throws IOException {    connect(snk);}/** * Creates a piped output stream that is not yet connected to a * piped input stream. It must be connected to a piped input stream, * either by the receiver or the sender, before being used. * * @see     java.io.PipedInputStream#connect(java.io.PipedOutputStream) * @see     java.io.PipedOutputStream#connect(java.io.PipedInputStream) */public PipedOutputStream() {}
2.2 PipedInputStream構造方法
/** * Creates a <code>PipedInputStream</code> so that it is * connected to the piped output stream * <code>src</code> and uses the specified pipe size for * the pipe's buffer. * Data bytes written to <code>src</code> will then * be available as input from this stream. * * @param      src   the stream to connect to. * @param      pipeSize the size of the pipe's buffer. * @exception  IOException  if an I/O error occurs. * @exception  IllegalArgumentException if {@code pipeSize <= 0}. * @since      1.6 */public PipedInputStream(PipedOutputStream src, int pipeSize)        throws IOException {    initPipe(pipeSize);    connect(src);}public PipedInputStream(PipedOutputStream src) throws IOException {    this(src, DEFAULT_PIPE_SIZE);}/** * Creates a <code>PipedInputStream</code> so that it is not yet * {@linkplain #connect(java.io.PipedOutputStream) connected} and * uses the specified pipe size for the pipe's buffer. * It must be {@linkplain java.io.PipedOutputStream#connect( * java.io.PipedInputStream) * connected} to a <code>PipedOutputStream</code> before being used. * * @param      pipeSize the size of the pipe's buffer. * @exception  IllegalArgumentException if {@code pipeSize <= 0}. * @since      1.6 */public PipedInputStream(int pipeSize) {    initPipe(pipeSize);}public PipedInputStream() {    initPipe(DEFAULT_PIPE_SIZE);}
2.3 PipedOutputStream connect方法
/** * Connects this piped output stream to a receiver. If this object * is already connected to some other piped input stream, an * <code>IOException</code> is thrown. * <p> * If <code>snk</code> is an unconnected piped input stream and * <code>src</code> is an unconnected piped output stream, they may * be connected by either the call: * <blockquote><pre> * src.connect(snk)</pre></blockquote> * or the call: * <blockquote><pre> * snk.connect(src)</pre></blockquote> * The two calls have the same effect. * * @param      snk   the piped input stream to connect to. * @exception  IOException  if an I/O error occurs. */public synchronized void connect(PipedInputStream snk) throws IOException {    if (snk == null) {        throw new NullPointerException();    } else if (sink != null || snk.connected) {        throw new IOException("Already connected");    }    sink = snk; //設定輸入資料流    snk.in = -1; //寫入緩衝區下標    snk.out = 0; //讀取緩衝區下標    snk.connected = true; //設定串連狀態}
2.4 PipedOutputStream write方法
/** * Writes the specified <code>byte</code> to the piped output stream. * <p> * Implements the <code>write</code> method of <code>OutputStream</code>. * * @param      b   the <code>byte</code> to be written. * @exception IOException if the pipe is <a href=#BROKEN> broken</a>, *          {@link #connect(java.io.PipedInputStream) unconnected}, *          closed, or if an I/O error occurs. */public void write(int b)  throws IOException {    if (sink == null) {        throw new IOException("Pipe not connected");    }    sink.receive(b); //直接調用輸入資料流方法操作輸入資料流緩衝區}/** * Receives a byte of data.  This method will block if no input is * available. * @param b the byte being received * @exception IOException If the pipe is <a href="#BROKEN"> <code>broken</code></a>, *          {@link #connect(java.io.PipedOutputStream) unconnected}, *          closed, or if an I/O error occurs. * @since     JDK1.1 */protected synchronized void receive(int b) throws IOException {    checkStateForReceive(); //檢查可寫入狀態    writeSide = Thread.currentThread(); //擷取輸入資料流線程    if (in == out) //滿,即緩衝區資料已讀取完        awaitSpace();    if (in < 0) { //緩衝區為空白        in = 0;        out = 0;    }    buffer[in++] = (byte)(b & 0xFF); //寫入,限定為8位    if (in >= buffer.length) { //        in = 0;    }}
2.5 PipedInputStream read方法
/** * Reads the next byte of data from this piped input stream. The * value byte is returned as an <code>int</code> in the range * <code>0</code> to <code>255</code>. * This method blocks until input data is available, the end of the * stream is detected, or an exception is thrown. * * @return     the next byte of data, or <code>-1</code> if the end of the *             stream is reached. * @exception  IOException  if the pipe is *           {@link #connect(java.io.PipedOutputStream) unconnected}, *           <a href="#BROKEN"> <code>broken</code></a>, closed, *           or if an I/O error occurs. */public synchronized int read()  throws IOException {    if (!connected) {        throw new IOException("Pipe not connected");    } else if (closedByReader) {        throw new IOException("Pipe closed");    } else if (writeSide != null && !writeSide.isAlive()            && !closedByWriter && (in < 0)) {        throw new IOException("Write end dead");    }    readSide = Thread.currentThread(); //擷取當前讀取線程    int trials = 2;    while (in < 0) { //沒有可讀內容        if (closedByWriter) {            /* closed by writer, return EOF */            return -1;        }        if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {            throw new IOException("Pipe broken");        }        /* might be a writer waiting */        notifyAll(); //通知寫入        try {            wait(1000);        } catch (InterruptedException ex) {            throw new java.io.InterruptedIOException();        }    }    int ret = buffer[out++] & 0xFF; //讀取位元組    if (out >= buffer.length) { //超過緩衝區長度,則從頭開始讀,寫的時候一樣,所以能保證讀寫一樣順序        out = 0;    }    if (in == out) { //沒有可讀內容        /* now empty */        in = -1; //receive中將out置為0    }    return ret;}
參考:

[1] http://www.cnblogs.com/skywang12345/p/io_04.html
[2] http://www.2cto.com/kf/201402/279143.html
[3] http://www.cnblogs.com/meng72ndsc/archive/2010/12/23/1915358.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.