java 什么是装饰流_jdk里面输入输出流的装饰者模式以及输入输出流的一些内容记录...

/**

* InputStream --> FilterInputStream --> (1.DataInputStream 2.BufferedInputStream 3.PushInputStream)

*

* DataInputStream:以与机器无关的方式来读取java的基础类型

*

* BufferedInputStream:由于基础输入流InputStream一个字节一个字节取读取,频繁与磁盘进行交互,造成读取速度较低,缓冲流的存在就是先将数据流读取到缓冲流中(也就是内存中),然后一次性从内存读取多个字符,提高读取的效率

*

*

* PushInputStream:回退输入流 java中读取流的方式是顺序读取,如果某个数据不需要读取,这个类就可以将某些不需要的数据回退到缓冲区

*/

/**

* FilterInputStream的所有子类都是为基础流提供一些额外的功能,为什么不直接继承了,非要来继承FilterInputStream。这就设计到了装饰者模式和继承的区别了

*/

/**

* 装饰着模式动态的将责任附加到对象上,若要增加功能,装饰者提供了比继承更具有弹性的替代方案

*

* 来 我来理解一下抽象组件,具体组件,抽象装饰者和具体装饰者

*

* 抽象组件:InputStream 具体组件FileInputStream等

*

*

* 抽象装饰者:FilterInputStream 具体装饰者 DataInputStream,BufferedInputStream

*/

/**

* 为什么具体组件和装饰者需要实现自抽象组件来保持类型一致

* 装饰者的优缺点

* 可以通过其他什么模式来避免装饰者的不足

*/

/**

* SocketOutputStream继承自FileOutputStream 充分说明了Socket也就是一个文件描述符

*/

/**

* 管道输入输出流PipedInputStream和PipedOutputStream

*

* 用处:通过管道进行线程间的通信

* 在线程A中向PipedOutputStream中写入数据,这些数据会自动发送到与PipedOutputStream对应的PipedInputStream中,进而存储在对应的缓冲区中

* 线程B通过读取PipedInputStream中的数据,来实现线程中的通信

*/

/**

* 灵魂拷问1:为什么字节输入流读取一个字节,返回的却是int类型,而不是一个byte类型

*

* 灵魂回答:字节输入流可以操作任意类型的的文件,比如音频图片等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到11111111(文件底层按补码来存储的)

*

* -1的源码 1000 0001

*

* -1的反码 1111 1110

*

* -1的补码 1111 1111

*

* 如果用int来表示的话

*

* 很明显-1自己就得在前面再加上三个字节 0000 0000 0000 0000 0000 0000 1111 1111 (255)

*

* 这样子就算读到中间的时候读到了-1表示的也不会返回,因为是按照int拼接之后返回的

*

* 但是结束标记的-1就是int类型表示的。

*

* 灵魂拷问2:为什么前面的数据都是一个字节一个字节的访问,结束符就是直接访问int类型了

*

* *********************************************************************************************

* 答:这个答案有点勉为其难,说什么结束标志的-1就是int类型。底层的数据读取机制看来还是很复杂的

* *********************************************************************************************

*/

PipedInputStream和PipedOutputStream源码

关联方法

pipedInputStream.connect(pipedOutputStream);

或者:pipedOutputStream.connect(pipedInputStream);

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;

}

PipedOutputStream:

private PipedInputStream sink;

pipedOutputStream.write(message.getBytes());

public void write(byte b[]) throws IOException {

write(b, 0, b.length);

}

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); //很明显write的数据最终都会被所关联的PipedInputStream所消费掉(receive)

}

PipedInputStream

*************************************************************

/** 在read的时候,如果Buffer里面没有数据,会阻塞

*

*/

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;

// in:next byte of data will be stored when received from the connected

// out:next byte of data will be read by this piped input stream

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;

}

******************************************************************************

public synchronized int read() throws IOException {

if (!connected) { // 判断是否连接了OutputStream

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(); // 获取到InputStream线程

int trials = 2;

while (in < 0) { // in<0 说明buffer里面没有数据

if (closedByWriter) { // 没有数据而且被OutputStream主动关闭了,肯定直接返回-1结束了

/* 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(); // 这里是唤醒写等待的,也就是OutputStream所属的线程,他们在buffer被写满的情况下会等待

try {

// 因为wait方法得调用,当前线程已经释放掉了锁,所以被notifyAll醒得线程就不需要等到同步代码块结束被被动释放得锁了,可以直接获取锁了,因为锁在同步代码块中就已经别释放掉了

wait(1000); // 这里是读等待,也就是InputStream所属的线程,他们在buffer为空,也就是in<0的情况下等待

} catch (InterruptedException ex) {

throw new java.io.InterruptedIOException();

}

}

// 从buffer里面取出来out对应的字节数据之后再把out加上1,方便后面判断buffer是否在这次取完之后就空了

int ret = buffer[out++] & 0xFF;

if (out >= buffer.length) {

out = 0;

}

if (in == out) {

/* now empty */

in = -1;

}

return ret;

}

*******************************************************************************

// 执行这个方法的线程是OutputStream所属的线程

synchronized void receive(byte b[], int off, int len) throws IOException {

checkStateForReceive();

writeSide = Thread.currentThread();

int bytesToTransfer = len;

while (bytesToTransfer > 0) {

if (in == out) // 如果in==out说明buffer是满的,那么写线程就得等待

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 {

nextTransferAmount = out - in;

}

}

if (nextTransferAmount > bytesToTransfer) // 这里还判断了一下buffer里面可供放置字节数据的地方是否能够容纳当前写入的数据

nextTransferAmount = bytesToTransfer;

assert(nextTransferAmount > 0);

System.arraycopy(b, off, buffer, in, nextTransferAmount);

bytesToTransfer -= nextTransferAmount; // 剩余多少,下次继续存入

off += nextTransferAmount;

in += nextTransferAmount;

if (in >= buffer.length) { // 如果in的值大于了当前buffer数组的长度,那么下标置为0,表示当前有数据可以读取,而且也可以从下标0开始继续写,感觉就是一个循环覆盖的过程,所以超过buffer字节大小的数据,它会重复覆盖掉之前的数据插入。

in = 0;

}

}

}

***********************************************************************

private void awaitSpace() throws IOException {

while (in == out) { // 这里持续阻塞啊 ,死循环,除非in != out 表示buffer有空闲的地方

checkStateForReceive();

/* full: kick any waiting readers */

notifyAll(); // 因为有数据,所以一直在通知等待在这个InputStream上面的读线程来读数据

try {

wait(1000); // 这里放出锁1000ms来给其他的对象获取做对应的操作

} catch (InterruptedException ex) {

throw new java.io.InterruptedIOException();

}

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值