1. 通过输入/输出在线程间进行通信通常很有用。提供线程功能的类库以“管道”的形式对线程间的输入/输出提供了支持。它们在Java输入/输出类库中的对应物就是PipedWriter类(允许任务向管道写)和PipedReader类(允许不同任务从同一个管道中读取)。这个模型可以看成是“生产者 - 消费者”问题的变体,这里的管道就是一个封装好的解决方案。管道基本上是一个阻塞队列,存在于多个引入BlockingQueue之前的Java版本中。

  2. 下面是一个简单例子,两个任务使用一个管道进行通信:

    Class :

package lime.thinkingInJava._021._005._005;

import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; /**
* @Author : Lime
* @Description :
* @Remark :
*/
class Sender implements Runnable{
private Random rand = new Random(47);
private PipedWriter out = new PipedWriter();
public PipedWriter getPipedWriter(){
return out;
}
public void run(){
try{
while (true){
for(char c = 'A'; c <= 'z';c++){
out.write(c);
TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));
}
}
} catch (InterruptedException e) {
System.out.println(e + " Sender sleep Interrupted");
} catch (IOException e) {
System.out.println(e + " Sender write exception");
}
}
}
class Receiver implements Runnable{
private PipedReader in;
public Receiver(Sender sender) throws IOException {
in = new PipedReader(sender.getPipedWriter());
}
public void run(){
try{
while (true){
//Blocks until characters are there;
System.out.println("Read : " + (char)in.read());
}
} catch (IOException e) {
System.out.println(e + " Receiver read exception");
}
}
}
public class PipedIO {
public static void main(String[] args) throws IOException, InterruptedException {
Sender sender = new Sender();
Receiver receiver = new Receiver(sender);
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(sender);
exec.execute(receiver);
TimeUnit.SECONDS.sleep(4);
exec.shutdownNow();
}
}

  3. Console :

Read : A
Read : B
Read : C
Read : D
Read : E
Read : F
Read : G
Read : H
Read : I
Read : J
Read : K
Read : L
Read : M
Read : N
Read : O
Read : P
Read : Q
java.lang.InterruptedException: sleep interrupted Sender sleep Interrupted
java.io.InterruptedIOException Receiver read exception

  4. Sender和Receiver代表了需要互相通信两个任务。Sender创建了一个PipedWriter,它是一个单独的对象;但是对于Receiver,PipedReader的建立必须在构造器中与一个PipedWriter相关联。Sender把数据放进Writer,然后休眠一段时间(随机数)。然而,Receiver没有Sleep()和wait()。但当它调用read()时,如果没有更多的数据,管道将自动阻塞。

  注意sender和receiver是在main()中启动的,即对象构造彻底完毕以后。如果你启动了一个没有构造完毕的对象,在不同的平台上管道可能会产生不一致的行为(注意,BlockingQueue使用起来更加健壮而容易)。

  在shutdownNow()被调用时,可以看到PipedReader与普通I/O之间最重要的差异 ------ PipedReader是可中断的。如果你将in.read()调用修改为System.in.read(),那么interrupt()将不能打断read()调用。

  5. PipedWriter的wirte() 源码解析

    /**
* Writes the specified <code>char</code> to the piped output stream.
* If a thread was reading data characters from the connected piped input
* stream, but the thread is no longer alive, then an
* <code>IOException</code> is thrown.
* <p>
* Implements the <code>write</code> method of <code>Writer</code>.
*
* @param c the <code>char</code> to be written.
* @exception IOException if the pipe is
* <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,
* {@link #connect(java.io.PipedReader) unconnected}, closed
* or an I/O error occurs.
*/
public void write(int c) throws IOException {
if (sink == null) {
throw new IOException("Pipe not connected");
}
//调用PipedReader的receive(c)方法,将c放入PipedReader的char buffer[]中
sink.receive(c);
}
    /**
* Receives a char of data. This method will block if no input is
* available.
*/
synchronized void receive(int c) throws IOException {
if (!connected) {
//判断两个I/O流连接状态
throw new IOException("Pipe not connected");
} else if (closedByWriter || closedByReader) {
//判断两个I/O流开启状态
throw new IOException("Pipe closed");
} else if (readSide != null && !readSide.isAlive()) {
//判断输入流线程是否存活
throw new IOException("Read end dead");
} //获取输出流线程
writeSide = Thread.currentThread();
while (in == out) {
//判断char buffer[] 是否已满
if ((readSide != null) && !readSide.isAlive()) {
//判断输入流状态是否存活
throw new IOException("Pipe broken");
}
/* full: kick any waiting readers */
// 间隔1000毫秒唤醒写线程 -- start
notifyAll();
try {
//阻塞1000毫秒
wait(1000);
} catch (InterruptedException ex) {
throw new java.io.InterruptedIOException();
}
// 间隔1000毫秒唤醒写线程 -- end
}
if (in < 0) {
//判断char buffer[] 为空
in = 0;
out = 0;
}
buffer[in++] = (char) c;
if (in >= buffer.length) {
in = 0;
}
}

  6. PipedRead的read() 源码解析

    /**
* Reads the next character of data from this piped stream.
* If no character is available because the end of the stream
* has been reached, the value <code>-1</code> is returned.
* This method blocks until input data is available, the end of
* the stream is detected, or an exception is thrown.
*
* @return the next character of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if the pipe is
* <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
* {@link #connect(java.io.PipedWriter) unconnected}, closed,
* or an I/O error occurs.
*/
public synchronized int read() throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByReader) {
throw new IOException("Pipe closed");
} else if (writeSide != null && !writeSide.isAlive()
&& !closedByWriter && (in < 0)) {
throw new IOException("Write end dead");
} readSide = Thread.currentThread();
//设定超时重连次数
int trials = 2;
while (in < 0) {
//判断char buffer[] 为空
if (closedByWriter) {
/* closed by writer, return EOF */
return -1;
}
if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
throw new IOException("Pipe broken");
}
/* might be a writer waiting */
// 间隔1000毫秒唤醒读线程 -- start
notifyAll();
try {
//阻塞1000毫秒
wait(1000);
} catch (InterruptedException ex) {
throw new java.io.InterruptedIOException();
}
// 间隔1000毫秒唤醒读线程 -- start
}
int ret = buffer[out++];
if (out >= buffer.length) {
out = 0;
}
if (in == out) {
/* now empty */
in = -1;
}
return ret;
}

  7. 鸣谢

    PipedWriter PipedReader 源码分析

啦啦啦

TIJ -- 任务间使用管道进行输入/输出的更多相关文章

  1. java 线程 生产者-消费者与队列,任务间使用管道进行输入、输出 解说演示样例 --thinking java4

    package org.rui.thread.block2; import java.io.BufferedReader; import java.io.IOException; import jav ...

  2. shell 通配符,管道符,输入/输出重定向,命令置换

    1. echo 输出   [echo 输出的内容 ]把内容输出到终端上 如果字符串使用双引号,echo命令原样输出   [ echo "hello       world" ]  ...

  3. 输入/输出系统的四种不同工作方式对CPU利用率比较

    程序控制工作方式:输入/输出完全由CPU控制,整个I/O过程中CPU必须等待其完成,因此对CPU的能力限制很大,利用率较低 程序中断工作方式:CPU不再定期查询I/O系统状态,而是当需要I/O处理时再 ...

  4. JAVA里面的IO流(一)分类1(字节/字符和输入/输出)

      java.io包中定义了多个流类型(流或抽象类)来实现输入/输出功能:可以从不同的角度对其进行分类: 按数据流的方向不同可以分为输入流和输出流 从文件读数据为输入流:往文件写数据为输出流 按处理数 ...

  5. [转]C语言文件输入/输出ACM改进版(freopen函数)

    C语言文件输入/输出ACM改进版(freopen函数) 2009年5月27日 10:379,457 浏览数发表评论阅读评论   文章作者:姜南(Slyar) 文章来源:Slyar Home (www. ...

  6. ubuntu12.04软件中心打开错误和 ubuntu 包管理之“:E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件包的列表或是状态文件。”的解决

    执行ubuntu软讲中心时打不开.老是崩溃,从终端也下载不了软件. 执行包管理的update或者search等等会报错: E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件 ...

  7. A Byte of Python 笔记(10)输入/输出:文件和储存器

    第12章  输入/输出 大多数情况下,我们需要程序与用户交互.从用户得到输入,然后打印一些结果. 可以分别使用 raw_input 和 print 语句来完成这些功能.对于输出,可以使用多种多样的 s ...

  8. Python基础学习笔记---5.输入\输出 I\O文件操作目录

    在很多时候,你会想要让你的程序与用户(可能是你自己)交互.你会从用户那里得到输入,然后打印一些结果.我们可以分别使用 raw_input 和 print 语句来完成这些功能.对于输出,你也可以使用多种 ...

  9. rm: 无法删除 "xxxxx.o" : 输入/输出错误.

    rm: 无法删除 "xxxxx.o" : 输入/输出错误. 碰到无法删除的文件,以为完蛋了,要重装. 后面重启一下就可以了

随机推荐

  1. [jzoj]1417.数学题

    Link https://jzoj.net/senior/#main/show/1417 Problem 当Alice在浏览数学书时,看到一个等式A=S,奇怪的是A和S并不相等.Alice发现可以通过 ...

  2. 使用itchat实现一个微信机器人聊天回复功能

    近看到好多群里都有一个@机器人的功能,挺有趣的,想自己也玩下,就通过百度一点点实现,在这总结一下整个从无到有的过程. 首先,要知道itchat,它是Python写的,所以想要实现这个机器人的功能,需要 ...

  3. MySQL解压版的安装与配置

    1.解压mysql-5.7.15-winx64.zip到D:\MySQL Server 5.7(你想安装的位置) 2.如果机器上安装过其他版本的mysql先删除环境变量PATH中的mysql路径,然后 ...

  4. 卷积cnn总结

    阅读了很多篇文章后,还是觉得有两篇文章很好,所以基本上就吸收搬过来了. 从神经网络到卷积神经网络(CNN) 我们知道神经网络的结构是这样的: 那卷积神经网络跟它是什么关系呢? 其实卷积神经网络依旧是层 ...

  5. lettcode21. Merge Two Sorted Lists

    lettcode21. Merge Two Sorted Lists Merge two sorted linked lists and return it as a new list. The ne ...

  6. 100本Python精品书籍(附pdf电子书下载)

    51本Python精品书籍(附下载)链接: https://pan.baidu.com/s/19ydAKCFxM0plkepXMlqQLg 提取码: nnpe 400集python视频教程下载:链接: ...

  7. SharePoint 修改用户属性User Name

    前言 最近,碰到一个奇怪的事情,在SharePoint里的用户,如果显示方式显示为登录名(Account)的方式,显示为空.如下图: 1.经过查找,发现是因为用户属性 User name为空造成的,如 ...

  8. Win10系统的SurfacePro4如何重装系统-3 重装完成之后的系统优化

    重装完成之后,还是有很多问题,比如触摸屏的驱动没了,你要接上去鼠标之后操作   由于Surface只有一个USB口,你接了鼠标,就没法接键盘,所以要开启屏幕的软键盘,右击任务栏,勾选显示触摸键盘按钮, ...

  9. 【打印】windows打印控件,Lodop.js介绍

    1.Lodop.js这插件很强大,目前仅支持windows系统 2.使用原生javascript编写 3.lodop支持客户端安装,c-lodop支持服务器端安装 4.无论客户端还是服务器端,都必须是 ...

  10. MySQL 5.5主从关于‘复制过滤’的深入探究

    关于MySQL主从复制的过滤,例如通过binlog-ignore-db.replicate-do-db.replicate-wild-do-table等.如果不好好研究过这些过滤选项就用的话,是有可能 ...