【Java】线程管道通讯

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

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

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

一、基本概念

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

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

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

完全可以在一个进程中设置一个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();
	}
}
时间: 2024-10-28 22:15:32

【Java】线程管道通讯的相关文章

Java 线程间通讯

/* 线程间通讯: 多个线程在处理同一资源,但是任务却不同. */ package com.cwcec.test; class Input implements Runnable { Resource r; public Input(Resource r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized (r) { if(x == 0) { r.name = "Mike"; r.sex

Java线程之间通讯(三)

使用wait和notify方法实现了线程间的通讯,都是Object 类的方法,java所有的对象都提供了这两个方法 1.wait和notify必须配合synchronized使用 2.wait方法释放锁,notify方法不释放锁 import java.util.ArrayList; import java.util.List; public class ListAdd1 { private volatile static List list = new ArrayList(); public

Java线程间通讯

考虑经典的排队问题,其中一个线程正在生产一些数据,另一个是消费它.为了使问题更有趣,假设生产者必须等待,直到它会产生更多的数据消费完毕之前. 在一个轮询系统,消费者会浪费大量的CPU周期,而它等待着生产者生产.一旦生产结束了,就开始轮询,浪费更多的CPU周期等待消费者??完成,依此类推.显然,这种情况是不希望的. 为了避免轮询,Java包括通过下面的方法优雅的进程间通信机制: wait( ): 这个方法告诉调用线程放弃监视器和进入睡眠状态,直到其他线程进入同一监视器和调用notify(). no

java 线程详解

5月7号  周末看了一下线程方面的内容 ,边看视频边看书还附带着参考了很多人的博客,一天的收获,写下来整理一下:感觉收获还是挺多的:过段时间可能看完java  这几大块要去看一下关于spring boot  的内容顺便  也整理一下:附上我参考的 几本书: 关于java  线程,首先要了解一下线程和进程之间的关系.区别以及他们之间的概念: 首先是线程: 什么是线程? 线程是在程序执行过程中能够执行部分代码的一个执行单元,也看看做是一个轻量级的进程:线程是程序内的程序控制流只能使用程序内分配给程序

Java NIO -- 管道 (Pipe)

Java NIO 管道是2个线程之间的单向数据连接. Pipe有一个source通道和一个sink通道.数据会被写到sink通道,从source通道读取. 举个例子: package com.soyoungboy.nio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import org.junit.Test; public class TestPipe { @Tes

关于java线程的一些了解

进程:就是正在运行的程序,分配内存让应用程序能够运行 Windows系统号称多任务(可以同时运行多个应用程序) 宏观上看:windows确实是允许多个程序 微观上看:CPU快速切换执行任务,由于速度特别快,我们人感觉不到这个切换的过程 线程:线程在一个进程中负责代码的执行,就是一个进程中的执行路径 疑问:没有学习线程,为什么代码可以执行 Java程序在运行的时候,jvm会帮我们创建一个主线程来执行代码.主线程主要负责main方法中的代码执行 一个java程序中至少有2个线程: 一个是主线程主要负

Java IO: 管道

原文链接 作者: Jakob Jenkov  译者: 李璟([email protected]) Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力.所以管道也可以作为数据源以及目标媒介. 你不能利用管道与不同的JVM中的线程通信(不同的进程).在概念上,Java的管道不同于Unix/Linux系统中的管道.在Unix/Linux中,运行在不同地址空间的两个进程可以通过管道通信.在Java中,通信的双方应该是运行在同一进程中的不同线程. 通过Java IO创建管道 可以通过J

java 多线程(0) Java线程

线程 线程是系统调度的基本单元,每当创建一个进程时,会有许多的线程,也叫轻量级进程,在一个进程中拥有多个线程,各自都有自己的计数器,堆和局部变量属性,并且能够分享内存变量. 为什么要使用多线程  1.更多的处理器核心 2.更快的响应时间 3.更好的编程模型 优先级 线程优先级决定了线程需要多或少分配一些处理器资源的线程属性,通过priority来控制优先级,范围从1-10,在线程构建SetPriority(int)方法来修改优先级,默认为5. 线程的运行状态 状态名称 说明 NEW 初始状态,线

Java线程栈的获取和分析

获取进程号 使用命令:jps 常用参数: -m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null. -l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径. -v 输出传给JVM的参数. 示例: 线程栈的获取 使用命令:jstack,通常使用管道将信息输出到文件,便于分析 常用参数: -F 当jstack没有响应的时候强制打印栈信息. -l 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表. -m