很多操作系统对于管道的吹嘘往往是天花龙凤,
好心点的就贴段伪代码给你看,为出书而出书的,就直接一堆概念堆在上面,让人根本看不懂,
如此简单的概念,明明几句话就解释清楚,有的书还专门开出一章来讨论这个问题,完全没有必要!
一、基本概念
其实管道的概念非常简单,就是连接两个线程通讯的缓冲区,画个图就更加明白了
写者进程把自己的数据通过管道输出流写入管道,读者进程再从管道通过管道输入流拿管道里面的数据
当然进程与进程之间传递数据未必通过这个方式去传递数据,
完全可以在一个进程中设置一个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); else System.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); else System.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(); } }