TIJ -- 任务间使用管道进行输入/输出

  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.

啦啦啦

时间: 2024-10-29 03:15:46

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

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

package org.rui.thread.block2; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedB

任务间使用管道进行输入输出

内容:通过输入/输出在线程间进行通信通常很有用.利用PipedWriter类(允许任务向管道写)和PipedReader类(允许不同任务从同一个管道中读取).下面代码中Sender和Receiver代表了需要相互通信的两个任务.Sender把数据放进Writer,然后休眠一段时间.然而,Receiver没有sleep()和wait().但当他调用read()时,如果没有更多的数据,管道将阻塞,而普通I/O是不能打断的. class Sender implements Runnable { pri

9、流类库与输入/输出

就像C语言一样,c++语言中也没有输入/输出语句.但c++编译系统带有一个面向对象的输入/输出软件爱你包,它就是I/O流类库. 1.I/O流的概念及流类库结构 I/O流类库是C语言中I/O函数在面向对象的程序设计方法中的一个替换产品. 当程序与外界环境进行信息交换时,存在着两个对象,一个是程序中的对象,另一个是文件对象. 流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动.程序建立一个流对象,并指定这个流对象与某个文件对象建立连接,程序操作流对象,流对象通过文件系统对

HeadFirstJava——12_序列化和文件的输入/输出

存储对象状态的方式: 1 序列化(若只有自己写的程序会用到这些数据) 创建一个文件,将被序列化的对象写入文件中,之后可在程序中到文件中读取序列化的对象并将其转换为状态: 注意:以文本文件形式阅读是无意义的: 2 写入纯文本文件中(若数据需要被其他程序引用) 创建一个文本文件,用其他程序可以解析的特殊字符写到文件中,每行写入一个对象的状态,用逗号/制表符分隔: 一.序列化 1 将序列化对象写入文件中 a 创建FileOutputStream 若MyGame.ser文件不存在,则自动被创建: 创建存

JavaScript-3.1--获取用户的输入,输出用户输入的两数之和---ShinePans

提示用户输入两个数,然后输出用户输入的两数之和 第一次输入 ,输入处为空 第二个输入,输入处为默认27  (这里强调语句的使用) <html> <head> <meta http-equiv="content-type" content="text/html;charset=GB2312"/> <title> 3.1 让用户输入两个数字,然后输出相加的结果 </title> </head> &l

2.4 基本的输入/输出操作

在C++输入/输出围绕着数据流这个概念,在数据流中,可以把数据插入输出流,或者从输入流析取数据.到屏幕上命令行的标准输出流称为cout,来自键盘的互补输入流称为cin.这两个流的名称都定义在std名称空间. 2.4.1 从键盘中输入 可以通过标准输入流cin从键盘获得输入,这时要使用流的析取运算符>>.要从键盘把两个整数值读入整型变量num1和num2,eg:std::cin >>num1 >>num2; 析取运算符>>“指向”数据流动的方向,本例中,数据是

输入 输出

字符 返回:来自输入设备的下一个字符 返回:成功返回下一个字符,出错或者达到文件结尾返回EOF 虽然函数被定义为整型数,但仅用其低八位 scanf 返回:成功返回读入项目的个数 检测到"文件结尾"时,返回EOF 行 fgets 返回:成功返回s,出错或达到文件结尾返回NULL fputs() 不为输出自动添加换行 gets()不足 它不检查余留存储区是否能够容纳实际输入数据 fgets() 指定最大读入字符数 终止位置:读出( size -1 ) 个字符或者读完一个换行符 '\n' 若

I/O(输入/输出)---字节流与字符流

流: 分为输入流和输出流,输入/输出是相对计算机内存来说的,数据输入到内存是输入流,数据从内存中输出是输出流. 流对象构造的时候会和数据源联系起来. 数据源分为:源数据源和目标数据源.输入流联系的是源数据源,输出流联系的是目标数据源. 按流向划分: 输入流:InputStream和Read 输出流:OutputStream和Write 输入流和输出流又分为字节流和字符流: 按处理数据单元划分: 字节流:InputStream和OutputStream.字节流是8位的通用字节流,基本单位是字节.

Java的输入/输出操作

Java的输入\输出机制 计算机的基本功能就是通过输入输出设备与外部其他设备尽心数据的交互,从其他设备读入数据叫做输入操作,将计算机内的数据写入到其他设备叫做输出操作.可以向计算机发送数据.又可以接受计算机数据的设备叫做输入/输出(I/O)设备,例如磁盘.网络等. Java中主要按照一种方式进行数据交换——流(Stream)的方式.流方式就好比是建立在数据交换源与目的地之间的一条通信路径.但是数据在作为流在该路径中进行传输.数据流的走向是有方向的,相对于计算机而言,传向计算机的数据流叫做输入流(