【Java多线程】——通过管道进行线程间通信

    在Java中提供了各种各样的输入输出流stream,我们可以用他们对数据进行方便的操作。其中,管道(pipeStream)是一种特殊的流,它可以用于在不同的线程之间传送数据。一个线程将数据输出到管道中,另一个线程从管道中读取需要的数据,实现不同线程之间的通信而无需通过临时文件。管道通信可以达到解耦的目的,产生数据的线程不需要直接调用处理数据的方法并等待返回结果,只需要将数据放入管道,接着继续执行自己的任务;而处理数据的线程直接从管道中拿出数据进行处理,不需要进行轮询来获取数据。

    Java的JDK中提供了四个类使得线程之间可以进行通信:

1)PipedInputStream和PipedOutputStream

2)PipedReader和PipedWriter

    下面用一个例子来实现线程间通过管道使用字节流进行通信:

//接受一个输出流参数,向输出流中写入数据
public class WriteData {

	public void writeData(PipedOutputStream out) {
		try {
			System.out.println("write:");
			for(int i=0;i<100;i++) {
				String outData = ""+(i+1);
				out.write(outData.getBytes());
				System.out.print(outData);
			}
			System.out.println();
			out.close();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
}
//接受一个输入流参数,读取数据
public class ReadData {
	public void readData(PipedInputStream input) {
		try {
			System.out.println("read:");
			byte[] byteArray = new byte[20];
			int readLength = input.read(byteArray);
			while(readLength!=-1) {
				String newData = new String(byteArray, 0, readLength);
				System.out.print(newData);
				readLength = input.read(byteArray);
			}
			System.out.println();
			input.close();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
}
//输出流线程
public class Thw extends Thread{
	private WriteData write;
	private PipedOutputStream out;
	public Thw(WriteData write, PipedOutputStream out) {
		super();
		this.write = write;
		this.out = out;
	}
	
	@Override
	public void run() {
		write.writeData(out);
	}
}
//输入流线程
public class Thr extends Thread{
	private ReadData read;
	private PipedInputStream input;
	public Thr(ReadData read, PipedInputStream input) {
		super();
		this.read = read;
		this.input = input;
	}
	@Override
	public void run() {
		read.readData(input);
	}
}
public class Run {
	public static void main(String args[]) {
		try {
			WriteData write = new WriteData();
			ReadData read = new ReadData();
			
			PipedOutputStream out = new PipedOutputStream();
			PipedInputStream input = new PipedInputStream();
			
			out.connect(input);
			
			Thw thw = new Thw(write, out);
			Thr thr = new Thr(read, input);
			
			thr.start();
			Thread.sleep(1000);
			thw.start();
			
		}catch(IOException e) {
			e.printStackTrace();
		}catch(InterruptedException ex) {
			ex.printStackTrace();	
		}
	}
}

运行以上程序可以看到如下运行结果:

/*

read:

write:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100

*/

    这里解释一下ReadData类中,readData方法的执行过程。首先创建一个长度为20的byte数组,并用input.read(byteArray)的返回结果初始化变量readLength,read(byteArray)默认返回read(byteArray,0,byteArray.length)的结果,其中三个参数分别表示,要将输入流中数据写入的目标数组,写入目标数组的起始下标,以及写入的长度。read()的源码如下:

public 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;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }
    可以看到,在jdk官方文档中有说明:

    If no byte is available because the stream is at the end of the file, the value -1 is returned;

    当输入流到达末尾时,会返回-1,且当readLength==-1时停止读取数据并关闭输入流。

    在主函数中,我们首先创建一个read线程,负责从输入流中读取数据并打印,然后启动。当执行到int readLength = input.read(byteArray);时,因为write线程还没有启动,所以没用数据写入,read线程被阻塞,直到有数据写入才继续向下运行。

猜你喜欢

转载自blog.csdn.net/u012198209/article/details/80335698