PipedReader和PipedWriter与PipedInputStream和PipedOutputStream一样,都可以用于管道通信。PipedWriter是字符管道输出流,继承于Writer;PipedReader是字符管道输入流,继承于Reader,PipedWriter和PipedReader的作用是可以通过管道进行线程间的通讯。两者必须要配套使用。

示例程序:

public class Receiver extends Thread {

    // 管道输入流对象。
    // 它和“管道输出流(PipedWriter)”对象绑定,
    // 从而可以接收“管道输出流”的数据,再让用户读取。
    private PipedReader in = new PipedReader();

    // 获得“管道输入流对象”
    public PipedReader getReader()
    {
        return in;
    }

    @Override
    public void run(){
        readMessageOnce() ;
        //readMessageContinued() ;
    }

    // 从“管道输入流”中读取1次数据
    public void readMessageOnce(){
        // 虽然buf的大小是2048个字符,但最多只会从“管道输入流”中读取1024个字符。
        // 因为,“管道输入流”的缓冲区大小默认只有1024个字符。
        char[] buf = new char[2048];
        try {
            int len = in.read(buf);
            System.out.println(new String(buf,0,len));
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 从“管道输入流”读取>1024个字符时,就停止读取
    public void readMessageContinued()
    {
        int total=0;
        while(true) {
            char[] buf = new char[1024];
            try {
                int len = in.read(buf);
                total += len;
                System.out.println(new String(buf,0,len));
                // 若读取的字符总数>1024,则退出循环。
                if (total > 1024)
                        break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

        try {
            in.close();
        } catch (IOException e) {
                e.printStackTrace();
        }
    }
}
public class Sender extends Thread {
    // 管道输出流对象。
    // 它和“管道输入流(PipedReader)”对象绑定,
    // 从而可以将数据发送给“管道输入流”的数据,然后用户可以从“管道输入流”读取数据。
    private PipedWriter out = new PipedWriter();
    // 获得“管道输出流”对象
    public PipedWriter getWriter(){
        return out;
    }

    @Override
    public void run(){
        writeShortMessage();
        //writeLongMessage();
    }

    // 向“管道输出流”中写入一则较简短的消息:"this is a short message"
    private void writeShortMessage() {
        String strInfo = "this is a short message" ;
        try {
            out.write(strInfo.toCharArray());
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 向“管道输出流”中写入一则较长的消息
    private void writeLongMessage() {
        StringBuilder sb = new StringBuilder();
        // 通过for循环写入1020个字符
        for (int i=0; i<102; i++)
            sb.append("0123456789");
            // 再写入26个字符。
            sb.append("abcdefghijklmnopqrstuvwxyz");
            // str的总长度是1020+26=1046个字符
            String str = sb.toString();
        try {
            // 将1046个字符写入到“管道输出流”中
            out.write(str);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class PipeTest {

    public static void main(String[] args) {
        Sender t1 = new Sender();   

        Receiver t2 = new Receiver();   

        PipedWriter out = t1.getWriter();   

        PipedReader in = t2.getReader();
        try {
            //管道连接。下面2句话的本质是一样。
            //out.connect(in);
            in.connect(out);   

            /**
            * Thread类的START方法:
            * 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
            * 结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。
            * 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
            */
            t1.start();
            t2.start();
        } catch (IOException e) {
             e.printStackTrace();
        }
    }
}
输出结果:
this is a short message

基于JDK8的PipedReader的源码:

public class PipedReader extends Reader {
    boolean closedByWriter = false;
    boolean closedByReader = false;
    boolean connected = false;

    /* REMIND: identification of the read and write sides needs to be
       more sophisticated.  Either using thread groups (but what about
       pipes within a thread?) or using finalization (but it may be a
       long time until the next GC). */
    Thread readSide;
    Thread writeSide;

    /**
     * The size of the pipe's circular input buffer.
     */
    //默认的输入缓冲大小为1024
    private static final int DEFAULT_PIPE_SIZE = 1024;

    /**
     * The circular buffer into which incoming data is placed.
     */
    //字符数组
    char buffer[];

    /**
     * The index of the position in the circular buffer at which the
     * next character of data will be stored when received from the connected
     * piped writer. <code>in<0</code> implies the buffer is empty,
     * <code>in==out</code> implies the buffer is full
     */
    //输入标志位
    int in = -1;

    /**
     * The index of the position in the circular buffer at which the next
     * character of data will be read by this piped reader.
     */
    //输出标志位,in==out表示为满
    int out = 0;
    //构造函数
    public PipedReader(PipedWriter src) throws IOException {
        this(src, DEFAULT_PIPE_SIZE);
    }
    //构造函数,有管道大小
    public PipedReader(PipedWriter src, int pipeSize) throws IOException {
        initPipe(pipeSize);
        connect(src);
    }
    //没有连接,必须链接才行
    public PipedReader() {
        initPipe(DEFAULT_PIPE_SIZE);
    }
    public PipedReader(int pipeSize) {
        initPipe(pipeSize);
    }
    //构建pipeSize大小的字符缓冲区
    private void initPipe(int pipeSize) {
        if (pipeSize <= 0) {
            throw new IllegalArgumentException("Pipe size <= 0");
        }
    buffer = new char[pipeSize];
    }
    //Reader与Writer连接
    public void connect(PipedWriter src) throws IOException {
        src.connect(this);
    }

    /**
     * Receives a char of data. This method will block if no input is
     * available.
     */
    //接受数据,
    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();
        while (in == out) {
            if ((readSide != null) && !readSide.isAlive()) {
                throw new IOException("Pipe broken");
            }
        /* full: kick any waiting readers */
        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;
        }
    }

    /**
     * Receives data into an array of characters.  This method will
     * block until some input is available.
     */
    synchronized void receive(char c[], int off, int len)  throws IOException {
        while (--len >= 0) {
            receive(c[off++]);
        }
    }

    /**
     * Notifies all waiting threads that the last character of data has been
     * received.
     */
    synchronized void receivedLast() {
        closedByWriter = true;
        notifyAll();
    }

    /**
     * Reads the next character of data from this piped stream.
     * If no character is available because the end of the stream
     * has been reached, the value <code>-1</code> is returned.
     * This method blocks until input data is available, the end of
     * the stream is detected, or an exception is thrown.
     *
     * @return     the next character of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if the pipe is
     *          <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
     *          {@link #connect(java.io.PipedWriter) unconnected}, closed,
     *          or 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++];
        if (out >= buffer.length) {
            out = 0;
        }
        if (in == out) {
            /* now empty */
            in = -1;
        }
        return ret;
    }

    /**
     * Reads up to <code>len</code> characters of data from this piped
     * stream into an array of characters. Less than <code>len</code> characters
     * will be read if the end of the data stream is reached or if
     * <code>len</code> exceeds the pipe's buffer size. This method
     * blocks until at least one character of input is available.
     *
     * @param      cbuf     the buffer into which the data is read.
     * @param      off   the start offset of the data.
     * @param      len   the maximum number of characters read.
     * @return     the total number of characters read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the stream has been reached.
     * @exception  IOException  if the pipe is
     *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
     *                  {@link #connect(java.io.PipedWriter) unconnected}, closed,
     *                  or an I/O error occurs.
     */
    public synchronized int read(char cbuf[], int off, int len)  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");
        }

        if ((off < 0) || (off > cbuf.length) || (len < 0) ||((off + len) > cbuf.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        /* possibly wait on the first character */
        int c = read();
        if (c < 0) {
            return -1;
        }
        cbuf[off] =  (char)c;
        int rlen = 1;
        while ((in >= 0) && (--len > 0)) {
            cbuf[off + rlen] = buffer[out++];
            rlen++;
            if (out >= buffer.length) {
                out = 0;
            }
            if (in == out) {
                /* now empty */
                in = -1;
            }
        }
        return rlen;
    }

    /**
     * Tell whether this stream is ready to be read.  A piped character
     * stream is ready if the circular buffer is not empty.
     *
     * @exception  IOException  if the pipe is
     *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
     *                  {@link #connect(java.io.PipedWriter) unconnected}, or closed.
     */
    //是否准备好可以读
    public synchronized boolean ready() 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");
        }
        if (in < 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Closes this piped stream and releases any system resources
     * associated with the stream.
     *
     * @exception  IOException  if an I/O error occurs.
     */
    //关闭管道流,释放资源
    public void close()  throws IOException {
        in = -1;
        closedByReader = true;
    }
}

基于JDK8的PipedWriter源码:

public class PipedWriter extends Writer {

        /* REMIND: identification of the read and write sides needs to be
       more sophisticated.  Either using thread groups (but what about
       pipes within a thread?) or using finalization (but it may be a
       long time until the next GC). */
        private PipedReader sink;

    /* This flag records the open status of this particular writer. It
     * is independent of the status flags defined in PipedReader. It is
     * used to do a sanity check on connect.
     */
    private boolean closed = false;

    /**
     * Creates a piped writer connected to the specified piped
     * reader. Data characters written to this stream will then be
     * available as input from <code>snk</code>.
     *
     * @param      snk   The piped reader to connect to.
     * @exception  IOException  if an I/O error occurs.
     */
    //构造函数,连接Reader
    public PipedWriter(PipedReader snk)  throws IOException {
        connect(snk);
    }

    /**
     * Creates a piped writer that is not yet connected to a
     * piped reader. It must be connected to a piped reader,
     * either by the receiver or the sender, before being used.
     *
     * @see     java.io.PipedReader#connect(java.io.PipedWriter)
     * @see     java.io.PipedWriter#connect(java.io.PipedReader)
     */
    public PipedWriter() {
    }
    //连接Reader,初始化in和out
    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;
    }
    //写字符
    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);
    }

    /**
     * Flushes this output stream and forces any buffered output characters
     * to be written out.
     * This will notify any readers that characters are waiting in the pipe.
     *
     * @exception  IOException  if the pipe is closed, or an I/O error occurs.
     */
    //刷新,强制缓存写出
    public synchronized void flush() throws IOException {
        if (sink != null) {
            if (sink.closedByReader || closed) {
                    throw new IOException("Pipe closed");
            }
            synchronized (sink) {
                sink.notifyAll();
            }
        }
    }

    /**
     * Closes this piped output stream and releases any system resources
     * associated with this stream. This stream may no longer be used for
     * writing characters.
     *
     * @exception  IOException  if an I/O error occurs.
     */
    public void close()  throws IOException {
        closed = true;
        if (sink != null) {
            sink.receivedLast();
        }
    }
}

Java-IO之PipedReader和PipedWriter的更多相关文章

  1. java io系列20之 PipedReader和PipedWriter

    本章,我们学习PipedReader和PipedWriter.它们和“PipedInputStream和PipedOutputStream”一样,都可以用于管道通信. PipedWriter 是字符管 ...

  2. Java IO(十三)PipedReader 和 PipedWriter

    Java IO(十三)PipedReader 和 PipedWriter 一.介绍 PipedReader 和 PipedWriter 分别是管道字符输入流和管道字符输出流,它们同 PipedInpu ...

  3. Java IO之字符流和文件

    前面的博文介绍了字节流,那字符流又是什么流?从字面意思上看,字节流是面向字节的流,字符流是针对unicode编码的字符流,字符的单位一般比字节大,字节可以处理任何数据类型,通常在处理文本文件内容时,字 ...

  4. java IO流详解

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  5. Java IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  6. [Java IO]03_字符流

    Java程序中,一个字符等于两个字节. Reader 和 Writer 两个就是专门用于操作字符流的类. Writer Writer是一个字符流的抽象类.  它的定义如下: public abstra ...

  7. java io 流分类表

    Java输入/输出流体系中常用的流分类(表内容来自java疯狂讲义) 注:下表中带下划线的是抽象类,不能创建对象.粗体部分是节点流,其他就是常用的处理流. 流分类 使用分类 字节输入流 字节输出流 字 ...

  8. java io 输入输出流

    数据流分类: 流序列中的数据既可以是未经加工的原始二进制数据, 也可以是经一定编码处理后符合某种格式规定的特定数据. 因此Java中的流分为两种: 1) 字节流:数据流中最小的数据单元是字节 2) 字 ...

  9. Java IO流体系中常用的流分类

    Java输入/输出流体系中常用的流分类(表内容来自java疯狂讲义) 注:下表中带下划线的是抽象类,不能创建对象.粗体部分是节点流,其他就是常用的处理流. 流分类 使用分类 字节输入流 字节输出流 字 ...

  10. java io系列01之 "目录"

    java io 系列目录如下: 01. java io系列01之  "目录" 02. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括 ...

随机推荐

  1. swift 初始化

    知识点总结: 1.结构体 1.1.默认初始化方法:1.空初始化方法:2.成员初始化方法 struct Person{ var name = "tom" var age = } le ...

  2. P20 旅行助手,从未有过的至尊私人导游服务!

    旅行可以让人暂时抛掉生活中的琐事,工作上的压力,寻找内心的宁静.有的人是为了想多去见识不同的事物和人文风情,有的人是想去感受大自然的馈赠,看历史古迹感受古人智慧.歌德说过:人之所以爱旅行,不是为了抵达 ...

  3. gulp将多张小图自动合成雪碧图

    最近一直在做移动端的改版项目,做之前老大就跟我说了好几次,说这次改版一定要用雪碧图减少一个页面的图片的请求次数,能加快页面的加载速度就一定要加快,我说可以.因为之前的项目开发时间过短,也没有时间去慢慢 ...

  4. thymeleaf:局部变量 th:with

    当th:with被处理,firstPer变量创建一个局部变量和变量添加到map自上下文,以便它是用于评估和其他上下文中声明的变量从开始,但只有包含< div >标记的范围内. <di ...

  5. linux系统下安装jdk、tomcat、mysql、redis

    一,安装jdk 1.rpm -qa | grep jdk 检测是否安装jdk 2.rpm -e --nodeps 要卸载的已有jdk名称 3.tar -zxvf jdk-7u71-linux-i586 ...

  6. Js删除数组函数

    引用地址:http://www.398588.com/Article/T8/96.aspx 众所周知大家都应该知道delete的用法,用来删除对象或者删除数组等,如果是删除对象除数组以外可能可以删除的 ...

  7. ASP.NET Core 添加统一模型验证处理机制

    一.前言 模型验证自ASP.NET MVC便有提供,我们可以在Model(DTO)的属性上加上数据注解(Data Annotations)特性,在进入Action之前便会根据数据注解,来验证输入的数据 ...

  8. ACM Adding Reversed Numbers(summer2017)

    The Antique Comedians of Malidinesia prefer comedies to tragedies. Unfortunately, most of the ancien ...

  9. PHP 5 Date/Time 函数

    PHP Date/Time 简介 Date/Time 函数允许您从 PHP 脚本运行的服务器上获取日期和时间.您可以使用 Date/Time 函数通过不同的方式来格式化日期和时间. 注释:这些函数依赖 ...

  10. sublime text package control 被墙的解决办法

    似乎没有办法 只能碰运气, 时好时坏. 或者手动安装 趁着好的时候, 下载离线包 https://packagecontrol.io/Package%20Control.sublime-package ...