5. 管道流
管道流是用来在多个线程之间进行信息传递的Java流,被号称是最难使用的流,被使用的频率也非常低。但事实上,管道流是非常有用的,它提供了多线程间信息传输的一种有效手段。
管道流包括两个类PipedOutputStream和PipedInputStream。其中PipedOutputStream是写入者/生产者/发送者;PipedInputStream是读取者/消费者/接收者。在使用管道流之前,需要注意以下要点:
第一,管道流仅用于多个线程之间传递信息,若用在同一个线程中可能会造成死锁;
第二,管道流的输入输出是成对的,一个输出流只能对应一个输入流,使用构造函数或者connect函数进行连接;
第三,一对管道流包含一个缓冲区,其默认值为1024个字节,若要改变缓冲区大小,可以使用带有参数的构造函数;
第四,管道的读写操作是互相阻塞的,当缓冲区为空时,读操作阻塞;当缓冲区满时,写操作阻塞;
第五,管道依附于线程,因此若线程结束,则虽然管道流对象还在,仍然会报错“read dead end”;
第六,管道流的读取方法与普通流不同,只有输出流正确close时,输出流才能读到-1值。
5.1 在管道中写入读取一个字符串
源代码一:在线程Sender中向管道流中写入一个字符串,写入后关闭该管道流;在线程Reciever中读取该字符串。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PipedStreamExam1 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
try {
//创建管道流
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
//创建线程对象
Sender sender = new Sender(pos);
Reciever reciever = new Reciever(pis);
//运行子线程
executorService.execute(sender);
executorService.execute(reciever);
} catch (IOException e) {
e.printStackTrace();
}
//等待子线程结束
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class Sender extends Thread {
private PipedOutputStream pos;
public Sender(PipedOutputStream pos) {
super();
this.pos = pos;
}
@Override
public void run() {
try {
String s = "This is a good day. 今天是个好天气。";
System.out.println("Sender:" + s);