java中PipedInputStream和PipedOutputStream分别是管道输入流和管道输出流,它的作用是让多线程可以通过管道进行线程间的通讯,在使用管道通信时,必须将PipedInputStream和PipedOutputStream配套使用。大致的流程是:当在线程A中向PipedOutputStream中写入数据,会自动发送到与PipedOutputStream对应的PipedInputStream中,进而存储在PipedInputStream的缓冲区中,此时线程B通过读取PipedInputStream中的数据,实现线程的通信。

PipedInputStream类的主要函数有:

public PipedInputStream(PipedOutputStream src)
public PipedInputStream(PipedOutputStream src, int pipeSize)
public PipedInputStream()
public PipedInputStream(int pipeSize)
public void connect(PipedOutputStream src)
protected synchronized void receive(int b)
synchronized void receive(byte b[], int off, int len)
public synchronized int read()
public synchronized int read(byte b[], int off, int len)
public synchronized int available()

PipedOutputStream类的主要函数有:

public PipedOutputStream(PipedInputStream snk)
public PipedOutputStream()
public synchronized void connect(PipedInputStream snk)
public void write(int b)
public void write(byte b[], int off, int len)

基于PipedInputStream和PipedOutputStream线程通信示例:

Send类:

public class Send extends Thread {

private PipedOutputStream outputStream=new PipedOutputStream();
    public PipedOutputStream getOutputStream()
    {
        return outputStream;
    }
    @Override
    public void run()
    {
        writeMessage();
    }

    public void writeMessage()
    {
        String string="hello pipedstream";
        try {
            outputStream.write(string.getBytes());
            outputStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Receiver类:

public class Receiver extends Thread{

    private PipedInputStream inputStream=new PipedInputStream();
    public PipedInputStream getInputStream()
    {
        return inputStream;
    }

    @Override
    public void run()
    {
        readMessage();
    }

    public void readMessage()
    {
        byte[] buf=new byte[2048];
        int len;
        try {
            len = inputStream.read(buf);
            System.out.println(new String(buf,0,len));
            inputStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Main函数:

public class Hello {

    public static void main(String [] args)
   {
        Send s1=new Send();
        Receiver r1=new Receiver();
        PipedInputStream inputStream=r1.getInputStream();
        PipedOutputStream outputStream=s1.getOutputStream();
      try {
         inputStream.connect(outputStream);
        s1.start();
        r1.start();
        } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }

   }
}
运行结果:
hello pipedstream
结果分析:
(1)inputStream.connect(outputStream);将管道输入流和输出流关联起来,代码换成outputStream.connect(inputStream)是同样的效果
(2)当调用PipedOutputStream的write()方法时,其实是调用的PipedInputStream的receiver()方法。

基于JDK8的PipedOutputStream的源码:

public class PipedOutputStream extends OutputStream {

   (but it may be a
       long time until the next GC). */
    private PipedInputStream sink;

    //构造函数,连接输出流
    public PipedOutputStream(PipedInputStream snk)  throws IOException {
        connect(snk);
    }

    //构造函数,并没有连接管道输入流,在使用之前必须进行连接
    public PipedOutputStream() {
    }

    //管道输出流和输入流进行连接,如果已经连接会抛出错误
    public synchronized void connect(PipedInputStream snk) throws IOException {
        if (snk == null) {
            throw new NullPointerException();
        } else if (sink != null || snk.connected) {
            throw new IOException("Already connected");
        }
        sink = snk;
        snk.in = -1;
        snk.out = 0;
        snk.connected = true;
    }

    //向输入流写数据
    public void write(int b)  throws IOException {
        if (sink == null) {
            throw new IOException("Pipe not connected");
        }
        sink.receive(b);
    }

    //想输入流写b,起始为off,长度为len
    public void write(byte b[], int off, int len) throws IOException {
        if (sink == null) {
            throw new IOException("Pipe not connected");
        } else if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                ((off + len) > b.length) || ((off + len) < 0)) {
                    throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        sink.receive(b, off, len);
    }

    //刷新,强制任意一个输出流都被写出
    public synchronized void flush() throws IOException {
        if (sink != null) {
            synchronized (sink) {
                sink.notifyAll();
            }
        }
    }
    //关闭输出流,释放资源
    public void close()  throws IOException {
        if (sink != null) {
            sink.receivedLast();
        }
    }
}

基于JDK8的PipedInputStream的源码:

public class PipedInputStream extends InputStream {
    boolean closedByWriter = false;
    volatile boolean closedByReader = false;
    boolean connected = false;
    Thread readSide;//读线程
    Thread writeSide;//写线程
    private static final int DEFAULT_PIPE_SIZE = 1024;//默认管道大小
    protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE;

    //字节数组,循环数组,放置数据
    protected byte buffer[];

    //写的标志位为-1
    protected int in = -1;

    //读的标志位为0,当in==out表示为空,
    protected int out = 0;

    //构造函数,连接输出流
    public PipedInputStream(PipedOutputStream src) throws IOException {
        this(src, DEFAULT_PIPE_SIZE);
    }

    //构造函数,连接输出流,并设置管道大小
    public PipedInputStream(PipedOutputStream src, int pipeSize)throws IOException {
        initPipe(pipeSize);
        connect(src);
    }

    //构造函数,还没有连接输出流
    public PipedInputStream() {
        initPipe(DEFAULT_PIPE_SIZE);
    }

    //设置管道大小
    public PipedInputStream(int pipeSize) {
        initPipe(pipeSize);
    }

    private void initPipe(int pipeSize) {
        if (pipeSize <= 0) {
            throw new IllegalArgumentException("Pipe Size <= 0");
        }
        buffer = new byte[pipeSize];
    }

    //连接输出流
    public void connect(PipedOutputStream src) throws IOException {
        src.connect(this);
    }

    //读取数据
    protected synchronized void receive(int b) throws IOException {
        checkStateForReceive();
        writeSide = Thread.currentThread();
        if (in == out)
            awaitSpace();
        if (in < 0) {
            in = 0;
            out = 0;
        }
        buffer[in++] = (byte)(b & 0xFF);
        if (in >= buffer.length) {
            in = 0;
        }
    }

    synchronized void receive(byte b[], int off, int len)  throws IOException {
        checkStateForReceive();
        writeSide = Thread.currentThread();
        int bytesToTransfer = len;
        while (bytesToTransfer > 0) {
            if (in == out)
                awaitSpace();
            int nextTransferAmount = 0;
            if (out < in) {
                nextTransferAmount = buffer.length - in;
            } else if (in < out) {
                if (in == -1) {
                    in = out = 0;
                    nextTransferAmount = buffer.length - in;
                } else {
                    nextTransferAmount = out - in;
                }
           }
        if (nextTransferAmount > bytesToTransfer)
                nextTransferAmount = bytesToTransfer;
            assert(nextTransferAmount > 0);
        System.arraycopy(b, off, buffer, in, nextTransferAmount);
        bytesToTransfer -= nextTransferAmount;
        off += nextTransferAmount;
        in += nextTransferAmount;
            if (in >= buffer.length) {
                in = 0;
            }
        }
    }

    private void checkStateForReceive() throws IOException {
        if (!connected) {
            throw new IOException("Pipe not connected");
        } else if (closedByWriter || closedByReader) {
            throw new IOException("Pipe closed");
        } else if (readSide != null && !readSide.isAlive()) {
            throw new IOException("Read end dead");
        }
    }

    private void awaitSpace() throws IOException {
        while (in == out) {
            checkStateForReceive();

            /* full: kick any waiting readers */
            notifyAll();
            try {
                wait(1000);
            } catch (InterruptedException ex) {
                throw new java.io.InterruptedIOException();
            }
        }
    }
    synchronized void receivedLast() {
        closedByWriter = true;
        notifyAll();
    }
    //从输入流中读取数据
    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) {
        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 */
        notifyAll();
            try {
                wait(1000);
            } catch (InterruptedException ex) {
                throw new java.io.InterruptedIOException();
            }
        }
        int ret = buffer[out++] & 0xFF;
        if (out >= buffer.length) {
            out = 0;
        }
        if (in == out) {
            /* now empty */
            in = -1;
        }

    return ret;
    }
    //从输入流中读取数据到b。其实为off,大小为len
    public synchronized int read(byte b[], int off, int len)  throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        /* possibly wait on the first character */
        int c = read();
        if (c < 0) {
            return -1;
        }
        b[off] = (byte) c;
        int rlen = 1;
        while ((in >= 0) && (len > 1)) {

            int available;

            if (in > out) {
                available = Math.min((buffer.length - out), (in - out));
            } else {
                available = buffer.length - out;
            }

            // A byte is read beforehand outside the loop
            if (available > (len - 1)) {
                available = len - 1;
            }
            System.arraycopy(buffer, out, b, off + rlen, available);
            out += available;
            rlen += available;
            len -= available;

            if (out >= buffer.length) {
                out = 0;
            }
            if (in == out) {
                /* now empty */
                in = -1;
            }
        }
        return rlen;
    }
    //判断是否还有数据
    public synchronized int available() throws IOException {
        if(in < 0)
            return 0;
        else if(in == out)
            return buffer.length;
        else if (in > out)
            return in - out;
        else
            return in + buffer.length - out;
    }
    //关闭资源
    public void close()  throws IOException {
        closedByReader = true;
        synchronized (this) {
            in = -1;
        }
    }
}

Java-IO之管道(PipedInputStream和PipedOutputStream)的更多相关文章

  1. 系统学习 Java IO (六)----管道流 PipedInputStream/PipedOutputStream

    目录:系统学习 Java IO---- 目录,概览 PipedInputStream 类使得可以作为字节流读取管道的内容. 管道是同一 JVM 内的线程之间的通信通道. 使用两个已连接的管道流时,要为 ...

  2. JAVA IO之管道流总结大全(转)

    要在文本框中显示控制台输出,我们必须用某种方法“截取”控制台流.换句话说,我们要有一种高效地读取写入到System.out和 System.err 所有内容的方法.如果你熟悉Java的管道流Piped ...

  3. Java I/O流-PipedInputStream、PipedOutputStream

    一.整体代码图 PipedStreamDemo.java import java.io.*; class PipedStreamDemo { public static void main(Strin ...

  4. java io之管道流

    一.java.io中存在一中流叫管道流,类似管道的功能.PipedOutputStream和PipedInputStream分别是管道输出流和管道输入流.这个两个流必须同时使用. 二.作用:进行两个线 ...

  5. java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例

    本章,我们对java 管道进行学习. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_04.html java 管道介绍 在java中,PipedOu ...

  6. Java IO: PipedInputStream

    原文链接 作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) PipedInputStream可以从管道中读取字节流数据,代码如下: 01 InputSt ...

  7. Java IO: 管道

    原文链接 作者: Jakob Jenkov  译者: 李璟(jlee381344197@gmail.com) Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力.所以管道也可以作为 ...

  8. Java IO学习--(三)通道

    Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力.所以管道也可以作为数据源以及目标媒介. 你不能利用管道与不同的JVM中的线程通信(不同的进程).在概念上,Java的管道不同于U ...

  9. Java基础17:Java IO流总结

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  10. 系统学习 Java IO ---- 目录,概览

    Java IO 类的系统教程,原创.主要参考自英文教程 Java IO Tutorial 和 Java Doc. http://tutorials.jenkov.com/java-io/index.h ...

随机推荐

  1. Machine Learning From Scratch-从头开始机器学习

    Python implementations of some of the fundamental Machine Learning models and algorithms from scratc ...

  2. java 学习笔记2 面向对象(上)

    类和对象 类是某一批对象的抽象,可以把类理解成某种概念.对象是一个具体存在的实体.类和对象是面向对象的核心. 类定义的是多个实例的特征,类不是具体存在,实例才是具体存在. 定义类(class)的语法: ...

  3. Matlab 编译EXE

    环境:vs2013  matlab2015b 一.生成独立可执行的程序(exe文件)步骤1.设置编译器.在matlab命令行输入mbuild –setup以及mex –setup,选择安装的c编译器. ...

  4. 查找Mysql的安装路径

    在安装Mysql后,却忘记路径了!!!!!!!! 查找的方法:进入Mysql命令行输入,   show variables like "%char%"; 红色部分就是Mysql的安 ...

  5. ionic tab页面跳转

    要使用到Tabs,现将Tabs导入 import { NavController, ModalController, Tabs } from 'ionic-angular'; 把要选择的Tabs页面的 ...

  6. Lucene总结

    数据的分类 结构化数据:有固定类型或者有固定长度的数据 例如:数据库中的数据(mysql,oracle等), 元数据(就是windows中的数据) 结构化数据搜索方法: 数据库中数据通过sql语句可以 ...

  7. Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355 大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法 ...

  8. Android图表库MPAndroidChart(十二)——来点不一样的,正负堆叠条形图

    Android图表库MPAndroidChart(十二)--来点不一样的,正负堆叠条形图 接上篇,今天要说的,和上篇的类似,只是方向是有相反的两面,我们先看下效果 实际上这样就导致了我们的代码是比较类 ...

  9. Hadoop 伪分布式安装、运行测试例子

    1. 配置linux系统环境 centos 6.4 下载地址:http://pan.baidu.com/s/1geoSWuv[VMWare专用CentOS.rar](安装打包好的VM压缩包) 并配置虚 ...

  10. Ubuntu Intel显卡驱动安装 (Ubuntu 14.04--Ubuntu 16.10 + Intel® Graphics Update Tool)

    最近使用在使用Ubuntu时,发现大部分情况下,不安装显卡驱动,使用默认驱动,都是没有问题的,但对于一些比较奇特配置的电脑,如下所示,如果使用默认驱动,会时常莫名其妙死机crash,尤其是在使用Ope ...