Java IO 中的管道为运行在同一个 JVM 中的两个线程提供了通信能力。因此管道既可以是数据源也可以是目标媒介。

阅读文章的过程中如果有任何疑问,欢迎添加笔者为好友,拉您进【七日书摘】微信交流群,一起交流技术,一起打造高质量的职场技术交流圈子,抱团取暖,共同进步。
七日书摘官方群.jpg
不能使用管道与不同 JVM(即不同进程) 中的线程进行通信,Java 中管道的概念不同于 Unix/Linux 系统中的管道概念。在 Unix/Linux 中,运行在不同地址空间的两个进程可以通过管道进行通信。但在 Java 中,通信的双方只能是运行在同一进程内的不同线程。

通过Java IO创建管道(Creating Pipes via Java IO)

可以通过 Java IO 中的 PipedOutputStream 和 PipedInputStream 创建管道。一个 PipedInputStream 流应该和一个 PipedOutputStream 流相关联。一个线程写入 PipedOutputStream 的数据可以被另一个线程通过相关联的 PipedInputStream 读取出来。

Java IO管道示例(Java IO Pipe Example)

下面是一个说明如何将 PipedInputStream 连接到PipedOutputStream 的简单的示例:

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipeExample {

    public static void main(String[] args) throws IOException {

        final PipedOutputStream output = new PipedOutputStream();
        final PipedInputStream  input  = new PipedInputStream(output);


        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    output.write("Hello world, pipe!".getBytes());
                } catch (IOException e) {
                }
            }
        });


        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    int data = input.read();
                    while(data != -1){
                        System.out.print((char) data);
                        data = input.read();
                    }
                } catch (IOException e) {
                }
            }
        });

        thread1.start();
        thread2.start();

    }
}
//编者注:本示例忽略了流使用后需要进行关闭。请各位童鞋在处理流的过程中,务必确保关闭流,或者使用 jdk7 引入的 try-resources 代替显示地调用 close 方法的方式进行关闭流操作。

你也可以使用两个管道流共有的 connect() 方法使之相关联。PipedInputStream 和 PipedOutputStream 都拥有一个可以互相关联的 connect() 方法。
示例如下:


import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipeExample2 {

    public static void main(String[] args) {
        try {
             PipedOutputStream output = new PipedOutputStream(); 
             PipedInputStream input = new PipedInputStream();
            // 使用 connect() 连接 output
            input.connect(output);

            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        output.write("Hello world, pipe!".getBytes());
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        int data = input.read();
                        while (data != -1) {
                            System.out.print((char) data);
                            data = input.read();
                        }
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

            thread1.start();
            thread2.start();
        } catch (Exception e) {
            // TODO:
        }
    }

}

管道和线程(Pipes and Threads)

同时请记住,当使用两个相关联/连接的管道流时,务必将它们分配给不同的线程。read() 方法和 write() 方法调用时会导致流阻塞,这意味着如果你尝试在同一个线程中同时进行读和写,这可能会导致线程死锁。

管道的替代方案(Pipe Alternatives)

除了管道之外,在一个 JVM 中不同线程之间的通信还有许多的方式。实际上,线程在大多数情况下会传递完整的对象信息而非原始的字节数据。但是,如果你需要在线程之间传递字节数据,Java IO 的管道是一个不错的选择。

英文原文链接:http://tutorials.jenkov.com/java-io/pipes.html

------完------

推荐阅读:

Java IO 基础 之 概述(Overview)

Java IO 基础 之 文件(Files)

Java IO 基础 之 流(Streams)

Java NIO 简明教程

更多学习讨论欢迎进入七日书摘官方群: 七日书摘官方群

七日书摘官方群群聊二维码.png

参考资料:
https://blog.csdn.net/i_am_kop/article/details/78513802
http://ifeve.com/java-io-%e7%ae%a1%e9%81%93/