Java PipedInputSream/PipedOutputStream的使用及源碼分析

PipedInputSream/PipedOutputStream

首先:這兩個類就是爲了在線程之間傳輸數據,通過使用這兩個類來實現各個程序模塊之間的鬆耦合通信。

一個PipedInputStream應該只一個PipedOutputStream 綁定,不然可能造成狀態混亂的。

關於其內部源碼的實現:

  1. 內部默認緩存數組大小1024

  2. PipedInputSream/PipedOutputStream這套機制的總體思想是阻塞的讀、寫緩存數組,這個緩存數組是PipedInputStream的成員變量。若數組爲空則Input阻塞等到緩存數組有數據寫入,若數組滿了則Output阻塞等到數組有空餘。

  3. 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();
    }
}

參考:http://www.cnblogs.com/skywang12345/p/io_04.html

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