管道

概述

管道流是用来在多个线程之间进行信息传递的Java流。

管道流分为字节流管道流和字符管道流。

字节管道流:PipedOutputStream 和 PipedInputStream。

字符管道流:PipedWriter 和 PipedReader。

字节管道流

这里我们只分析字节管道流,字符管道流原理跟字节管道流一样,只不过底层一个是 byte[] 存储 一个是 char[] 存储的。

java的管道输入与输出实际上使用的是一个循环缓冲数来实现的。

输入流PipedInputStream从这个循环缓冲数组中读数据,输出流PipedOutputStream往这个循环缓冲数组中写入数据。

当这个缓冲数组已满的时候,输出流PipedOutputStream所在的线程将阻塞;当这个缓冲数组为空的时候,输入流PipedInputStream所在的线程将阻塞。

注意事项

  • 管道流仅用于多个线程之间传递信息,若用在同一个线程中可能会造成死锁;

  • 管道流的输入输出是成对的,一个输出流只能对应一个输入流,使用构造函数或者 connect() 函数进行连接;

  • 一对管道流包含一个缓冲区,其默认值为1024个字节,若要改变缓冲区大小,可以使用带有参数的构造函数;

  • 管道的读写操作是互相阻塞的,当缓冲区为空时,读操作阻塞;当缓冲区满时,写操作阻塞;

  • 管道依附于线程,因此若线程结束,则虽然管道流对象还在,仍然会报错“read dead end”;

  • 管道流的读取方法与普通流不同,只有输出流正确close时,输出流才能读到-1值。

实际代码

  • PipeTest
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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(); } }

输出日志

  [plaintext]
1
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