在UNIX/Linux中有一个很有用的概念——管道(pipe),它具有将一个程序的输出当作另一个程序的输入的能力。
在Java中,它的 I/O系统建立在数据流概念之上,也可以使用“管道”流进行线程之间的通信,在这个机制中,输入流和输出流必须相连接,这样的通信有别于一般的共享数据(Shared Data)缓冲区通信,其不需要一个共享的数据空间。
管道流主要用于连接两个线程间的通信。管道流也分为字节流(PipedInputStream、PipedOutputStream)与字符流(PipedReader、PipedWriter)两种类型.
一个PipedInputStream对象必须和一个PipedOutputStream对象进行连接而产生一个通信管道, PipedOutputStream可以向管道中写入数据,PipedInputStream可以从管道中读取PipedOutputStream写入的数据。
如下图所示,这两个类主要用来完成线程之间的通信,一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据:
package com.xy.io;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipeStreamDemo {
public static void main(String[] args) {
try {
Sender sender = new Sender(); // 创建线程对象Sender
Receiver receiver = new Receiver(); // 创建线程对象Receiver
PipedOutputStream out = sender.getOutputStream(); // 写入
PipedInputStream in = receiver.getInputStream(); // 读出
out.connect(in); // 将输出发送到输入
sender.start();// 启动线程
receiver.start();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
class Sender extends Thread {
private PipedOutputStream out = new PipedOutputStream();
public PipedOutputStream getOutputStream() {
return out;
}
public void run() {
String s = new String("Receiver,你好!");
try {
out.write(s.getBytes());
out.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
class Receiver extends Thread {
private PipedInputStream in = new PipedInputStream();
public PipedInputStream getInputStream() {
return in;
}
public void run() {
String s = null;
byte[] b = new byte[1024];
try {
int len = in.read(b);
s = new String(b, 0, len);
System.out.println("收到了以下信息:" + s);
in.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
【结果】
此外,注意到第48行,声明的字节数组大小为1024,其实这是有讲究的:
类PipedInputStream运用的是一个1024字节固定大小的循环缓冲区。 实际上,写入PipedOutputStream的数据保存到对应的 PipedInputStream的内部缓冲区。如果对应的 PipedInputStream输入缓冲区已满,再次企图写入PipedOutputStream的线程都将被阻塞,直至出现读取PipedInputStream的操作从缓冲区删除数据。