通过学习PipedInputStream和PipedOutputStream代码,发现有两点值得我们学习:
1、notifyAll(), wait(1000); 先把对象上所有的等待线程唤醒,然后把自己睡去一定时间后醒来。 和我们平时写生产者消费者时wait(), notifyAll()有一点点不一样。
2、处理循环buffer的方式不一样,用in==-1来表示buffer为空,同时处理buffer时是常常一段一段读取(如write()里的nextTransferAmount)。
具体内容自己去读sun的源代码,详细对生产者和消费者写法会有新的认识。
下面我们给出两个对PipedInputStream和PipedOutputStream使用的例子来体会他们的用法:
package org.study.io;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipedStreamTest {
/**
* @param args
*/
public static void main(String[] args) {
Producer p = new Producer();
Consumer c = new Consumer();
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
try {
p.getPipedOutputStream().connect(c.getPipedInputStream());
t2.start();
t1.start();
} catch (IOException e) {
e.printStackTrace();
}
}
private static class Producer implements Runnable {
private PipedOutputStream pos;
public Producer() {
pos = new PipedOutputStream();
}
public PipedOutputStream getPipedOutputStream() {
return pos;
}
@Override
public void run() {
try {
for (int i = 1; i <= 10; i++) {
pos.write(("This is a testing message, messageId=" + i + "\n").getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
pos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static class Consumer implements Runnable {
private PipedInputStream pis;
public Consumer() {
pis = new PipedInputStream();
}
public PipedInputStream getPipedInputStream() {
return pis;
}
@Override
public void run() {
int len = -1;
byte[] buffer = new byte[1024];
try {
//read(buffer, 0, buffer.length)函数作用有两个:
//(1)若有buffer.length个数据可读,则返回buffer.length个数据;
// 否则读取当前可读的所有数据,个数小于buffer.length;
//(2)若没有数据可读,则让读进程等待(见read()函数)
while ((len = pis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
pis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注: PipedInputStream和PipedOutStream适用于两个线程之间通信,不适合多个线程之间通信。因为PipedInputStream里的writeSide和readSide获得了对线程的引用,多个线程通信的话,这两个变量经常变化,引起PipedInputStream的函数不能正常工作,故不适合多个线程之间通信。
测试代码如下:
package org.study.io;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipedMultiThreadTest {
/**
* @param args
*/
public static void main(String[] args) {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
try {
pis.connect(pos);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Producer p = new Producer(pos);
Consumer c = new Consumer(pis);
Thread tp1 = new Thread(p, "生产者1号");
Thread tp2 = new Thread(p, "生产者2号");
Thread tp3 = new Thread(p, "生产者3号");
Thread tp4 = new Thread(p, "生产者4号");
Thread tp5 = new Thread(p, "生产者5号");
Thread tc1 = new Thread(c, "消费者1号");
Thread tc2 = new Thread(c, "消费者2号");
Thread tc3 = new Thread(c, "消费者3号");
Thread tc4 = new Thread(c, "消费者4号");
Thread tc5 = new Thread(c, "消费者5号");
tc1.start();
tc2.start();
tc3.start();
tc4.start();
tp1.start();
tp2.start();
tc5.start();
tp3.start();
tp4.start();
tp5.start();
}
private static class Producer implements Runnable {
private PipedOutputStream pos;
public Producer(PipedOutputStream pos) {
this.pos = pos;
}
@Override
public void run() {
try {
for (int i = 1; i <= 10; i++) {
pos.write(("threadName="+Thread.currentThread().getName()+", messageId=" + i + "\n").getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static class Consumer implements Runnable {
private PipedInputStream pis;
public Consumer(PipedInputStream pis) {
this.pis = pis;
}
@Override
public void run() {
int len = -1;
byte[] buffer = new byte[1024];
try {
//read(buffer, 0, buffer.length)函数作用有两个:
//(1)若有buffer.length个数据可读,则返回buffer.length个数据;
// 否则读取当前可读的所有数据,个数小于buffer.length;
//(2)若没有数据可读,则让读进程等待(见read()函数)
while ((len = pis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}