管道流提供在对象间传输数据的基本手段例如当2个线程间需要传输数据时,不能直接传输,需要设置一个存放数据的缓冲区,并要考虑线程间同步问题。而采用管道流即可解决同样的问题,并简化操作。
管道流提供在对象间传输数据的基本手段。它分为I/O流,也可分为字符/字节流。一次数据传输操作需要2个管道流对象:一个输入流对象,一个输出流对象两个管道流对象需要在建立连接后,才允许一个对象向输出流对象写入数据,另一个对象从输入流对象读取数据
1)以PipedInputStream为例分析:
在java类中的层次关系如下:
主要有4个属性域:
protected byte[] buffer :用于存放输入数据的循环缓冲区
protected int in :表示从已连接的管道输出流获取的下一字节的数据在循环缓冲区中的位置索引
protected int out :表示即将被该管道输入流读取的下一字节数据在循环缓冲区中的位置索引
protected static int PIPESIZE :表示该管道的循环输入缓冲区的默认大小
主要提供6个方法:
int available() //返回在没有阻塞的前提下,能够从该输入流读取的总的数据字节数
void close() //关闭该输入流并释放相关的系统资源
void connect(PipedOutputStream src) //与管道输出流src建立连接
int read() //从该管道输入流读取下一字节数据
int read(byte[] b,int off,int len) //从该管道输入流的缓冲区中下标为off处连续读取len字节的数据到字节数组b中
protected void receive(int b) //接收b字节数据
2)程序实例演示
实现一个简单的发牌程序
有一个发送线程Sender对象向N个管道输出流共发送X张牌。每个发送线程对象有N个管道输出流,同时有N个接收线程Receiver对象分别从管道输入流中接收牌,每个接收线程对象需要一个管道输入流。默认取N=4,X=52。
程序完整源代码如下:
import java.io.*;
/**
* 管道流提供在对象间传输数据的基本手段。它分为I/O流,也可分为字符/字节流。
* 一次数据传输操作需要2个管道流对象:一个输入流对象,一个输出流对象
* 2个管道流对象需要在建立连接后,才允许向输出流对象写入数据,从输入流对象读取数据
* 本例演示管道流的使用方法,实现发牌程序
* 有一个发送线程Sender对象向N个管道输出流共发送X张牌。每个发送线程对象有N个管道输出流
* 同时有N个接收线程Receiver对象分别从管道输入流中接收牌,每个接收线程对象需要一个管道输入流
* 默认取N=4,X=52。
* @author Haiyuan
* 2013-4-3 上午10:19:26
*/
//发牌程序
public class SendCard {
public SendCard(int n) throws IOException{//n表示玩牌的人数
PipedInputStream[] in = new PipedInputStream[n];//管道输入流对象数组
PipedOutputStream[] out = new PipedOutputStream[n];//管道输出流对象数组
for(int i=0;i<in.length;i++){
in[i] = new PipedInputStream(); //创建一个管道输入流对象
out[i] = new PipedOutputStream(in[i]); //创建一个管道输出流对象并建立连接
}
Sender sender = new Sender(out); //创建一个发送线程
sender.start();
try {
sender.sleep(100);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
for(int i=0;i<in.length;i++){ //启动多个接收线程
Receiver receiver = new Receiver(in[i]);
receiver.start();
try {
receiver.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public SendCard() throws IOException{
this(4); //默认4人玩牌
}
public static void main(String[] args) throws IOException {
new SendCard();
}
}
class Sender extends Thread{ //发送线程
private PipedOutputStream[] out;
private int max; //最大牌数
public Sender(PipedOutputStream[] out,int max){
this.out = out;
this.max = max;
}
public Sender(PipedOutputStream[] out){
this(out,52); //默认52张牌
}
public void run(){//线程体
System.out.println("Sender: ");
//按序依次将52张牌轮流发给各个玩家:此处实现为将1~52的整数轮流写到各管道输出流中
int k = 1;
try{
while(k<=this.max){
for(int i=0;i<out.length&&k<=this.max;i++){//一个for循环语句实现一轮发牌
this.out[i].write(k);
if(k%27==0)
System.out.println();
System.out.print(k+" ");
k++;
}
}
for(int i=0;i<out.length;i++){//发牌完成后,关闭所有的管道输出流
this.out[i].close();
}
System.out.println();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
}
class Receiver extends Thread{ //接收线程
private PipedInputStream in;
public Receiver(PipedInputStream in){
this.in = in;
}
public void run(){
System.out.print("Reveiver——"+this.getName()+": ");
try{
int i= -1;
do{ //输入流未结束时
i = this.in.read();
if(i!=-1)
System.out.print(i+" ");
}while(i!=-1);
System.out.println();
this.in.close();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
}