(五)PipedInputStream与PipedOutputStream
来源:互联网 发布:excel数组 编辑:程序博客网 时间:2024/05/21 00:19
PipedInputStream与PipedOutputStream需要配套使用,用于同一个进程之间不同线程的通信。
首先先看一下PipedOutputStream源码
//内部持有一个PipedInputStream的引用,通过connect()将两者绑定在一起,当然通过PipedInputStream.connect也可以进行绑定,效果都是一样的,后面可以看到。private PipedInputStream sink; public PipedOutputStream(PipedInputStream snk) throws IOException { connect(snk); } public PipedOutputStream() { } 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; }
//观察write()函数可以发现,写入的数据通过PipedInputStream.receive()传到了PipedInputStream内部,自身并没有进行任何数据的缓存。 public void write(int b) throws IOException { if (sink == null) { throw new IOException("Pipe not connected"); } sink.receive(b); } public void write(byte b[], int off, int len) throws IOException { if (sink == null) { throw new IOException("Pipe not connected"); } else if (b == null) { throw new NullPointerException(); } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } sink.receive(b, off, len); }
//刷新函数也只是读线程激活。 public synchronized void flush() throws IOException { if (sink != null) { synchronized (sink) { sink.notifyAll(); } } } //关闭流也是通过持有输入流引用进行,receivedLast()函数主要是激活所有读线程开始读取。 public void close() throws IOException { if (sink != null) { sink.receivedLast(); } }
PipedOutputStream的源码比较简单,重点还是要分析一下PipedInputStream源码
boolean closedByWriter = false;//输出流是否关闭 volatile boolean closedByReader = false;//输入流是否关闭 boolean connected = false;//是否关联 Thread readSide;//当前读线程 Thread writeSide;//当前写线程 //缓存区大小 private static final int DEFAULT_PIPE_SIZE = 1024; protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE; //缓存数组 protected byte buffer[]; //存储下标 protected int in = -1; //读取下标 protected int out = 0; //当in == out表示缓存区所有数据都已读
//构造函数可以设置缓存区大小 public PipedInputStream(PipedOutputStream src) throws IOException { this(src, DEFAULT_PIPE_SIZE); } public PipedInputStream(PipedOutputStream src, int pipeSize) throws IOException { initPipe(pipeSize); connect(src); } public PipedInputStream() { initPipe(DEFAULT_PIPE_SIZE); } public PipedInputStream(int pipeSize) { initPipe(pipeSize); } private void initPipe(int pipeSize) { if (pipeSize <= 0) { throw new IllegalArgumentException("Pipe Size <= 0"); } buffer = new byte[pipeSize]; } //connect函数可以进行输入/输出流的绑定 //最后调用的还是PipedOutputStream.connect() public void connect(PipedOutputStream src) throws IOException { src.connect(this); }
//当输出流输出数据时被调用,数据都过该函数存储到输入流中//这两个函数只会被PipedOutputStream实例通过PipedInputStream引用进行调用。 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); if (in >= buffer.length) {//循环数组 in = 0; } } synchronized void receive(byte b[], int off, int len) throws IOException { checkStateForReceive(); writeSide = Thread.currentThread(); int bytesToTransfer = len; //循环写入,直到结束 while (bytesToTransfer > 0) { if (in == out)//等待数据写入 awaitSpace(); int nextTransferAmount = 0; //这一段用于计算可存储长度 if (out < in) {//读取比写入慢 nextTransferAmount = buffer.length - in; } else if (in < out) { if (in == -1) {//整个数组可存 in = out = 0; nextTransferAmount = buffer.length - in; } else {//buffer[in]~buffer[out]之间的数据是读过的,buffer[out]-buffer[buffer.length-1]和buffer[0]~buffer[in]的数据是未读的 nextTransferAmount = out - in; } } //取最小 if (nextTransferAmount > bytesToTransfer) nextTransferAmount = bytesToTransfer; assert(nextTransferAmount > 0); System.arraycopy(b, off, buffer, in, nextTransferAmount); bytesToTransfer -= nextTransferAmount; off += nextTransferAmount; in += nextTransferAmount; if (in >= buffer.length) { in = 0; } } }
private void checkStateForReceive() 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"); } } private void awaitSpace() throws IOException { while (in == out) { checkStateForReceive(); /* full: kick any waiting readers */ notifyAll(); try { wait(1000); } catch (InterruptedException ex) { throw new java.io.InterruptedIOException(); } } } synchronized void receivedLast() { closedByWriter = true; notifyAll(); }
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; } return ret; } public synchronized int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } /* possibly wait on the first character */ int c = read(); if (c < 0) { return -1; } b[off] = (byte) c; int rlen = 1; while ((in >= 0) && (len > 1)) { int available; if (in > out) { available = Math.min((buffer.length - out), (in - out)); } else { available = buffer.length - out; } // A byte is read beforehand outside the loop if (available > (len - 1)) { available = len - 1; } System.arraycopy(buffer, out, b, off + rlen, available); out += available; rlen += available; len -= available; if (out >= buffer.length) { out = 0; } if (in == out) { /* now empty */ in = -1; } } return rlen; }
总结
- 通过PipedOutputStream输出的数据直接写入到PipedInputStream的缓存数组中了。
- 当写线程写入数据时,发现没有空间写入时,激活所有读线程读取数据并阻塞自身线程,直到有空间写入或被读线程所通知。
- 当读线程读取数据,发现没有数据可读时,通知所有写线程写入数据并阻塞自身线程,直到有数据可读或被写线程通知。
阅读全文
0 0
- (五)PipedInputStream与PipedOutputStream
- PipedInputStream与PipedOutputStream
- PipedInputStream与PipedOutputStream类
- PipedInputStream & PipedOutputStream
- PipedInputStream类与PipedOutputStream类完全解析
- 管道流PipedInputStream与PipedOutputStream操作实例
- Java8 I/O源码-PipedInputStream与PipedOutputStream
- Java IO(八):PipedInputStream & PipedOutputStream
- java IO笔记(PipedInputStream/PipedOutputStream)
- IO 输入与输出(3) -- 节点流之四PipedInputStream和PipedOutputStream
- PipedInputStream&&PipedOutputStream使用
- Java.PipedInputStream-PipedOutputStream
- 管道PipedInputStream/PipedOutputStream类
- 从PipedInputStream/PipedOutputStream谈起
- PipedInputStream和PipedOutputStream
- 使用PipedOutputStream和PipedInputStream
- 管道PipedInputStream/PipedOutputStream类
- 从PipedInputStream/PipedOutputStream谈起
- 多线程编程学习::POSIX 多线程基础(二)
- SpringBoot学习(一)
- Mysql之查询
- Torch中多GPU运行代码学习
- Java手动实现简单 ArrayList
- (五)PipedInputStream与PipedOutputStream
- Hibernate
- 免费领取微软OneDrive网盘5T容量,非扩容!
- hdu4812 D Tree
- HDU 2700 Parity(签到)
- ZooKeeper 分布式安装手册:
- 遍历聚合对象中的元素——迭代器模式(二)
- Hibernate5在MySQL数据库中自动建表时报异常Error executing DDL via JDBC Statement
- javascirpt实现2个iframe之间传值的方法