管道
概述
管道流是用来在多个线程之间进行信息传递的Java流。
管道流分为字节流管道流和字符管道流。
字节管道流:PipedOutputStream 和 PipedInputStream。
字符管道流:PipedWriter 和 PipedReader。
字节管道流
这里我们只分析字节管道流,字符管道流原理跟字节管道流一样,只不过底层一个是 byte[]
存储 一个是 char[]
存储的。
java的管道输入与输出实际上使用的是一个循环缓冲数来实现的。
输入流PipedInputStream从这个循环缓冲数组中读数据,输出流PipedOutputStream往这个循环缓冲数组中写入数据。
当这个缓冲数组已满的时候,输出流PipedOutputStream所在的线程将阻塞;当这个缓冲数组为空的时候,输入流PipedInputStream所在的线程将阻塞。
注意事项
-
管道流仅用于多个线程之间传递信息,若用在同一个线程中可能会造成死锁;
-
管道流的输入输出是成对的,一个输出流只能对应一个输入流,使用构造函数或者
connect()
函数进行连接; -
一对管道流包含一个缓冲区,其默认值为1024个字节,若要改变缓冲区大小,可以使用带有参数的构造函数;
-
管道的读写操作是互相阻塞的,当缓冲区为空时,读操作阻塞;当缓冲区满时,写操作阻塞;
-
管道依附于线程,因此若线程结束,则虽然管道流对象还在,仍然会报错“read dead end”;
-
管道流的读取方法与普通流不同,只有输出流正确close时,输出流才能读到-1值。
实际代码
- PipeTest
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipeTest {
public static void main(String[] args) throws IOException {
final PipedOutputStream output = new PipedOutputStream();
final PipedInputStream input = new PipedInputStream(output);
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
output.write("Hello world, pipe!".getBytes());
} catch (IOException e) {
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
} catch (IOException e) {
}
}
});
thread1.start();
thread2.start();
}
}
输出日志
Hello world, pipe!
参考资料
http://ifeve.com/java-io-%E7%AE%A1%E9%81%93/
https://blog.csdn.net/yhl_jxy/article/details/79283851
https://www.cnblogs.com/skywang12345/p/io_04.html
https://www.jianshu.com/p/e1416f026c3d
- 源码分析
https://my.oschina.net/zhangyq1991/blog/1861126