
版权声明:http://blog.csdn.net/qq924862077/
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();
- }
- }
- }