Java并发编程艺术 - 管道输入和输出流

Java管道

管道连接输入流和输出流。

管道I/O基于生产者 - 消费者模式,其中生产者产生数据,而消费者消费数据。在管道I/O中,创建两个流代表管道的两端。

PipedOutputStream对象表示流的一端,PipedInputStream对象则表示流的另一端。使用两个对象的connect()方法连接两端。

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
@Slf4j
public class PipedStreamTest {
public static void main(String[] args) throws InterruptedException {
PipedStreamReceive pipedStreamReceive1 = new PipedStreamReceive("receive1");

//指定输入管道
PipedStreamSend pipedStreamSend1 = new PipedStreamSend("send1", pipedStreamReceive1.pipedInputStream);

Thread thread1 = new Thread(pipedStreamSend1.runnable);
Thread thread2 = new Thread(pipedStreamReceive1.runnable);

thread1.start();
//等先发一下
Thread.sleep(5000);
thread2.start();
}


@Data
public static class PipedStreamSend {

//初始化
private PipedOutputStream pipedOutputStream = new PipedOutputStream();
private PipedInputStream pipedInputStream;
//消息内容
private AtomicInteger num = new AtomicInteger(0);

//输入流管道标识
private String name;

public PipedStreamSend(String name, PipedInputStream pipedInputStream) {
this.name = name;
this.pipedInputStream = pipedInputStream;
}

private Runnable runnable = () -> {
try {
//连接输入管道
pipedOutputStream.connect(pipedInputStream);

while (true) {
//写入流
pipedOutputStream.write(num.incrementAndGet());
//刷新缓冲
pipedOutputStream.flush();
log.info("name:{},num:{}", this.name, this.num.get());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
};
}

@Data
public static class PipedStreamReceive {

//初始化
private PipedInputStream pipedInputStream = new PipedInputStream();

//输入流管道标识
private String name;

public PipedStreamReceive(String name) {
this.name = name;
}

private Runnable runnable = () -> {
try {
int num;
//读取流
while ((num = pipedInputStream.read()) != -1) {
log.info("name:{},num:{}", name, num);
}
} catch (IOException e) {
e.printStackTrace();
}
};
}
}

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
name:send1,num:1
name:send1,num:2
name:send1,num:3
name:send1,num:4
name:send1,num:5
name:receive1,num:1
name:receive1,num:2
name:receive1,num:3
name:receive1,num:4
name:receive1,num:5
name:receive1,num:6
name:send1,num:6

优缺点

优点:

  • 创建管道输出流PipedOutputStream pos和管道输入流PipedInputStream pis
  • 将pos和pis匹配,pos.connect(pis);
  • 将pos赋给信息输入线程,pis赋给信息获取线程,就可以实现线程间的通讯了

缺点:

  • 管道流只能在两个线程之间传递数据
  • 管道流只能实现单向发送,如果要两个线程之间互通讯,则需要两个管道流

总结

作为线程通讯方式之一,可以看到管道流使用起来很方便,但是制约也很大,具体使用要看实际的需求,如果项目中只有两个线程持续传递消息,那用管道流也很方便,如果项目中有很多个线程之间需要通讯,那还是用共享变量的方式来传递消息比较方便。

------ 本文结束------

本文标题:Java并发编程艺术 - 管道输入和输出流

文章作者:Perkins

发布时间:2019年09月09日

原始链接:https://perkins4j2.github.io/posts/18201/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。