PipedInputSream/PipedOutputStream
首先:这两个类就是为了在线程之间传输数据,通过使用这两个类来实现各个程序模块之间的松耦合通信。
一个PipedInputStream应该只一个PipedOutputStream 绑定,不然可能造成状态混乱的。
关于其内部源码的实现:
内部默认缓存数组大小1024
PipedInputSream/PipedOutputStream这套机制的总体思想是阻塞的读、写缓存数组,这个缓存数组是PipedInputStream的成员变量。若数组为空则Input阻塞等到缓存数组有数据写入,若数组满了则Output阻塞等到数组有空余。
PipedOutputStream的write()内部其实是调用的PipedInputStream的receive()方法,且该方法是synchronized 修饰的。receive方法内部当缓存数组写满是,就会调用wait(1000)阻塞住调用PipedOutputStream的write线程,直到缓存数组可写。
而当调用PipedInputStream的read()方法时,如果缓存数组为空,read()方法内部也会调用wait(1000)阻塞当前的read线程,直到缓存数组中有数据写入
举个栗子:
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Arrays;
class Producer extends Thread {
PipedOutputStream outputStream;
public Producer(PipedInputStream inputStream) throws IOException {
this.outputStream = new PipedOutputStream(inputStream);
}
private void produce() throws IOException {
byte[] data1 = "Hello Consumer.我是生产者".getBytes();
System.out.println("data1 len=" + data1.length);
System.out.println("data2 len=10240");
byte[] data2 = new byte[1024 * 10];
for (int i = 0; i < 1024 * 10; i++) {
data2[i] = 3;
}
this.outputStream.write(data1);
System.out.println("producer wrote data1");
this.outputStream.write(data2);
System.out.println("producer wrote data2");
outputStream.close();
/**
这里要记得关闭输出流。这个close被override了,这个函数内部是调用了PipedInputStream中的receivedLast函数,其会设置PipedInputStream的成员变量closedByWriter 为true,从而下次read的时候返回-1
如果没有关闭的话,producer线程直接退出,会导致consumer在read的时候抛错:java.io.IOException: Write end dead。
receivedLast源码,JDK1.7
synchronized void receivedLast() {
closedByWriter = true;
notifyAll();//通知还在阻塞等待的read线程或write线程。
}
**/
}
@Override
public void run() {
try {
produce();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Consumer extends Thread {
PipedInputStream inputStream = new PipedInputStream();
private void consume() throws IOException {
byte[] buf = new byte[2048];
int offset = this.inputStream.read(buf);
System.out.println("consumer read data1:" + new String(Arrays.copyOfRange(buf, 0, 15 + 5 * 3)));//不指定编码的话,将采用系统默认编码。本机默认编码是UTF-8。因此因此英文占1字节,中文占3字节
int data2Len = offset - 30;
while (offset != -1) {
offset = this.inputStream.read(buf);
if (offset != -1) data2Len += offset;
}
System.out.println("consumer read data2 len:" + data2Len);
inputStream.close();
}
public PipedInputStream getInputStream() {
return inputStream;
}
@Override
public void run() {
try {
consume();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class PipedStream {
public static void main(String[] args) throws IOException {
String defaultCharsetName = Charset.defaultCharset().displayName();
System.out.println("defaultCharsetName:" + defaultCharsetName);//获取默认编码字符
Consumer consumer = new Consumer();
Producer producer = new Producer(consumer.getInputStream());
consumer.start();
producer.start();
}
}