[重学Java基础][Java IO流][Part.5]管道字符输入输出流

[重学Java基础][JavaIO流][Part.5]管道字符输入输出流

PipedReader

概述

PipedReader管道输入流 需要配合管道输出流PipedWriter使用 用于线程间通讯
在线程间开启一个管道 互相传输数据

源码分析

成员变量

   PipedWriter对象是否关闭
   boolean closedByWriter = false;
   PipedReader对象是否关闭
   boolean closedByReader = false;
   连接是否关闭
   boolean connected = false;
   进行读入的线程
   Thread readSide;
   进行写出的线程
   Thread writeSide;
   默认的缓冲字符数组大小
   private static final int DEFAULT_PIPE_SIZE = 1024;
   缓冲字符数组
   char buffer[];
   下一个从管道读入到缓冲数组的字符游标位置 如果in==out说明已经读入完毕
   int in = -1;
   int out = 0;

这里写图片描述

成员方法

构造函数 可以自主制定管道缓冲大小或者使用默认值 指定与PipedReader相连的PipedWriter 对象

public PipedReader() {
        initPipe(DEFAULT_PIPE_SIZE);
    }

public PipedReader(int pipeSize) {
        initPipe(pipeSize);
    }

public PipedReader(PipedWriter src) throws IOException {
        this(src, DEFAULT_PIPE_SIZE);
    }

public PipedReader(PipedWriter src, int pipeSize) throws IOException {
        initPipe(pipeSize);
        connect(src);
    }

连接 实际上调用的是PipedWriter 对象的connect()方法

 public void connect(PipedWriter src) throws IOException {
        src.connect(this);
    }

接收方法

接收字符数据 只会在PipedWriter的write(int b)中会被调用
    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();

        每隔1s检查“管道状态”,并唤醒管道操作
        若有“读取管道数据线程被阻塞”,则唤醒该线程
        直到数据被全部读取(in==out)
        while (in == out) {
            if ((readSide != null) && !readSide.isAlive()) {
                throw new IOException("Pipe broken");
            }
            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;
        }
    }

    按字符读入 并制定起始位置和读入长度
    synchronized void receive(char c[], int off, int len)  throws IOException {
        while (--len >= 0) {
            receive(c[off++]);
        }
    }

接受完毕 通知所有线程此管道被关闭

synchronized void receivedLast() {
    closedByWriter = true;
    notifyAll();
}

读取方法和其他字符输入流读取类似 内容省略


PipedWriter

概述

源码分析

Alt text

成员变量

PipedReader对象用于和PipedWriter通信
private PipedReader sink;

 PipedWriter的关闭标记
private boolean closed = false;

成员方法

构造方法 可以指定连接的PipedReader 对象或者稍后指定

public PipedWriter(PipedReader snk)  throws IOException {
    connect(snk);
}


public PipedWriter() {
}

连接方法 将此字符输出管道连接到输入管道上

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;
    设置Reader对象的连接状态为成功
    snk.connected = true;
 }

刷新管道方法 调用了PipedReader sink的notifyAll()方法 使当前的PipedReader 放弃对资源的占用 唤醒其他被阻塞的PipedReader 读取PipedWriter的值

public synchronized void flush() throws IOException {
    if (sink != null) {
        if (sink.closedByReader || closed) {
            throw new IOException("Pipe closed");
        }
        synchronized (sink) {
            sink.notifyAll();
        }
    }
}

写入方法 实际上是调用了PipedReader sink的接收方法

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);
}

PipedReader PipedWriter综合代码示例

发送端

class Sender extends Thread {

//发送端端设置一个内部类PipedWriter的实例对象out用于发送管道数据
private PipedWriter out = new PipedWriter();

// 获得“管道输出流”对象
public PipedWriter getWriter(){
    return out;
}

@Override
public void run(){
    writeShortMessage();

    try {
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    System.out.println("Sender Over");

}

// 向“管道输出流”中写入数据
private void writeShortMessage() {
    String strInfo = "this is message sender" ;
    try {
        out.write(strInfo.toCharArray());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}
接收端

class Receiver extends Thread {

//接收端设置一个内部类PipedReader的实例对象in用于接受管道数据
private PipedReader in = new PipedReader();

//获取这个PipedReader对象 用于从外部设置接收端和发送端的连接
public PipedReader getReader(){
    return in;
}

@Override
public void run(){
    readMessage() ;
    //必须全部读取完毕才能关闭连接 否则会报错
    try {
        in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    System.out.println("Receiver Over");
}

// 从“管道输入流”中读取1次数据 需要自己截断 因为写入端是连续写入的
public void readMessage(){
    char[] buf = new char[23];
    try {
        in.read(buf);
        System.out.println(new String(buf,0,23));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}
运行主函数

public static void main(String[] args) throws IOException {

    Sender sender=new Sender();

    Receiver receiver=new Receiver();

    sender.getWriter().connect(receiver.getReader());

    sender.start();
    receiver.start();
}

运行结果

this is message sender 
Sender Over
Receiver Over

猜你喜欢

转载自blog.csdn.net/u011863951/article/details/80004516