Java IO类库之PipedWriter

1、PipedWriter介绍

    PipedWriter是字符管道输出流,继承自Writer,功能与PipedOutputStream相似,经过与PipedReader组合使用实现相似管道的功能,在多线程环境下,一个线程使用PipedWriter写入数据,经过管道将数据传递到管道另外一端的字符输入流内部缓冲区(实际是经过当前字符管道输出流绑定的字符管道输入流对象sink的receive方法将数据存储到字符输入流的内部字符缓冲区实现的),其余线程去读该内部缓冲区的字符数据,实现线程间通讯。java

2、PipedWriter类成员变量

package java.io;

public class PipedWriter extends Writer {

    /** 管道绑定的字符输入流对象 **/
    private PipedReader sink;

    /* 
     * 当前管道字符输出流的状态,独立于管道另外一端字符输入流的状态
     */
    private boolean closed = false;

}

3、PipedWriter源码分析

1 - 构造函数

/**
    * 构造函数,调用connect为当前对象与指定字符管道输入流对象创建链接
    */
   public PipedWriter(PipedReader snk)  throws IOException {
        connect(snk);
    }

    /**
     * 构造函数,空实现,还没与管道的字符输入流创建链接,在使用以前必须先创建链接不管是管道数据接收端PipedReader仍是
     * 仍是数据写入端PipedWriter调用connect创建链接
     */
    public PipedWriter() {
    }

    PipedWriter的构造函数逻辑很是简单,两种构造函数一种什么都没作只是建立一个未创建管道链接的对象,另外一个构造函数在实例化的同时调用connect建立了与指定字符管道输入流对象的管道链接,以后PipedWriter主要是基于这个指定的管道输入流对象操做管道数据。数组

2 - void write(int c)方法 - 写入单个字符

public void write(int c)  throws IOException {
        if (sink == null) {
            throw new IOException("Pipe not connected");
        }
        sink.receive(c);
    }

    方法逻辑很简单就是在开头作了管道绑定的接收端字符管道输入流对象sink的判空,若不为空则调用它的receive方法接收写入的单个字符c,receive的内部方法逻辑可参照上篇PipedReader对于receive方法的解析多线程

3 - 其余成员方法

/**
     * 为当前管道输出流对象链接指定的管道输入流对象snk,若当前管道输出流以前已经创建与其余字符管道输入流的链接则抛出
     * IOException异常
     */
    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;
        snk.connected = true;
    }


    /**
     * 将指定字符数组cbuf从off位置开始len个字符写入管道绑定的字符管道输入流对象内部缓冲区中
     * 若是一个线程正在读取链接的字符管道输入流内部缓冲区字节数据,这时候当前线程挂掉那么会抛出一个IO异常
     */
    public void write(char cbuf[], int off, int len) throws IOException {
        //管道绑定的字符管道输入流对象为空
        if (sink == null) {
            throw new IOException("Pipe not connected");
        } 
        /** 校验字符数组起始位置参数off **/
        else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
            throw new IndexOutOfBoundsException();
        }
        //将字符数组数据写入管道绑定的字符输入流内部缓冲区
        sink.receive(cbuf, off, len);
    }

    /**
     * 刷新管道输出流,主要是经过唤醒管道输入流等待读取线程读取数据实现刷新的。
     */
    public synchronized void flush() throws IOException {
        if (sink != null) {
            if (sink.closedByReader || closed) {
                throw new IOException("Pipe closed");
            }
            synchronized (sink) {
                sink.notifyAll();
            }
        }
    }

    /**
     * 关闭当前管道输出流对象,释放与此有关的系统资源,实际是调用绑定的管道输入流对象sink的reveivedLast方法
     * 更新sink管道写入端状态成员变量closedByWriter并唤醒其余等待线程
     */
    public void close()  throws IOException {
        closed = true;
        if (sink != null) {
            sink.receivedLast();
        }
    }
相关文章
相关标签/搜索