Java IO:PipedOutputStream和PipedInputStream使用详解及源码分析

来源:互联网 发布:devcpp使用教程c语言 编辑:程序博客网 时间:2024/04/29 01:41

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

0 0
原创粉丝点击