【Java】线程管道通讯

来源:互联网 发布:国家数据共享交换平台 编辑:程序博客网 时间:2024/05/01 16:58

很多操作系统对于管道的吹嘘往往是天花龙凤,

好心点的就贴段伪代码给你看,为出书而出书的,就直接一堆概念堆在上面,让人根本看不懂,

如此简单的概念,明明几句话就解释清楚,有的书还专门开出一章来讨论这个问题,完全没有必要!


一、基本概念

其实管道的概念非常简单,就是连接两个线程通讯的缓冲区,画个图就更加明白了


写者进程把自己的数据通过管道输出流写入管道,读者进程再从管道通过管道输入流拿管道里面的数据

当然进程与进程之间传递数据未必通过这个方式去传递数据,

完全可以在一个进程中设置一个public变量,然后再另一个进程用.+成员变量访问,当然这样可能会被批什么耦合度高的鬼东西

管道在线程之间传递数据传递数据,只是其中一个方法,当然如果你要考研,或者考操作系统,一定要好好掌握这个内容,其实也不难,就是一个简单的Java程序,简单得都不知道有什么用~


二、基本目标

有这样的一个程序:


写者进程每250毫秒工作一次,不停地对管道输出数据,直到输出到10,

读者则每500毫秒工作一次,不停地从管道读取数据,直到读完

如果读者比写者工作速度快,也就是读者请求第一个数据,写者还没开始写,本来我以为这样要出错的,经过试验,发现一旦管道输入输出流建立起来之后,不加上close()方法,读者必须等待写者写出数据才读,直到写者写完所有为止。

然后,我还以为管道通讯,必须双开管道流才不会出错,结果发现关掉其中一头,程序是不会报错的,只是一头使劲在写/读,直到写/读完。

最后,我还试能否有两个读者从管道中取数据,结果发现是不行的,管道必须是一对一的,假如有一个写者,多个读者,就只有一个读者能够读到管道的所有数据,而其余读者什么都读不到。


三、制作过程

注意先在头部引入java.io.*包由于用到了输入输出流

1、首先是主函数:

public class PipeThread {public static void main(String args[]) throws IOException {PipedOutputStream pos = new PipedOutputStream();PipedInputStream pis = new PipedInputStream(pos);new Writer(pos).start();new Reader(pis).start();}}

管道输出流可以无参数创建,

管道输入流必须根据管道输出流创建,否则Java会爆“管道流”无法建立的异常

然后把管道输出流与管道输入流扔到写者进程与读者进程,这里两个进程必须用构造函数来实现这两个管道流的获取,不能再其中的run()进程设置参数,这是Java的默认参数


2、然后是写者进程:

class Writer extends Thread {private PipedOutputStream pos;public Writer(PipedOutputStream pos) {this.pos = pos;}public void run() {PrintStream p = new PrintStream(pos);for (int i = 1; i < 11; i++) {try {Thread.currentThread().sleep(250);} catch (Exception e) {}p.println(i);System.out.println("Write:" + i);}System.out.println("已经写入完毕");p.flush();p.close();}}
一开始是写者的构造函数,声明这里用到的管道输出流就是主函数那个传过来的管道输出流,

之后用打印流,每个250s把内容打印流到管道里面并输出到屏幕,至于什么是打印流,可以参考我之前的《【Java】打印流与缓冲区读者完成输入与输出到文件操作》(点击打开链接),然后Java进程怎么用,可以参考我之前的《【Java】线程并发、互斥与同步》(点击打开链接)

然后关闭打印流之前,用flush()清空一下内存里面的内容,其实不清,不关打印流也没有关系的,你的windows系统会自动处理这些东西的。


3、最后是读进程:

class Reader extends Thread {private PipedInputStream pis;private String line;public Reader(PipedInputStream pis) {this.pis = pis;}public void run() {BufferedReader r = new BufferedReader(new InputStreamReader(pis));try {do {line = r.readLine();if (line != null)System.out.println("Read:" + line);elseSystem.out.println("已经读取完毕");Thread.currentThread().sleep(500);} while (r != null && line != null);} catch (Exception e) {}}}

一开始的构造函数保证了这个管道输入流,就是主函数那个已经与管道输出流连接起来的管道输入流

缓冲区读者,从输入流不停地读数据,且这个输入流是从管道输入流来读取的,读完为止,至于什么是缓冲区读者,可以参考我之前的《【Java】打印流与缓冲区读者完成输入与输出到文件操作》(点击打开链接),打印流与缓冲区读者是Java中很常见的读、写机制,必须要弄懂。

因此,整个程序如下:

import java.io.*;class Writer extends Thread {private PipedOutputStream pos;public Writer(PipedOutputStream pos) {this.pos = pos;}public void run() {PrintStream p = new PrintStream(pos);for (int i = 1; i < 11; i++) {try {Thread.currentThread().sleep(250);} catch (Exception e) {}p.println(i);System.out.println("Write:" + i);}System.out.println("已经写入完毕");p.flush();p.close();}}class Reader extends Thread {private PipedInputStream pis;private String line;public Reader(PipedInputStream pis) {this.pis = pis;}public void run() {BufferedReader r = new BufferedReader(new InputStreamReader(pis));try {do {line = r.readLine();if (line != null)System.out.println("Read:" + line);elseSystem.out.println("已经读取完毕");Thread.currentThread().sleep(500);} while (r != null && line != null);} catch (Exception e) {}}}public class PipeThread {public static void main(String args[]) throws IOException {PipedOutputStream pos = new PipedOutputStream();PipedInputStream pis = new PipedInputStream(pos);new Writer(pos).start();new Reader(pis).start();}}


1 0