Using Pipes for I/O between threads
It’s often useful for threads to communicate with each other by using I/O. Threading libraries may provide support for inter-thread I/O in the form of pipes. These exist in the Java I/O library as the classes PipedWriter (which allows a thread to write into a pipe) and PipedReader (which allows a different thread to read from the same pipe). This can be thought of as a variation of the producer-consumer problem, where the pipe is the canned solution.
Here’s a simple example in which two threads use a pipe to communicate:
//: c13:PipedIO.java
// Using pipes for inter-thread I/O
import java.io.*;
import java.util.*;
class Sender extends Thread {
private Random rand = new Random();
private PipedWriter out = new PipedWriter();
public PipedWriter getPipedWriter() { return out; }
public void run() {
while(true) {
for(char c = 'A'; c <= 'z'; c++) {
try {
out.write(c);
sleep(rand.nextInt(500));
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
class Receiver extends Thread {
private PipedReader in;
public Receiver(Sender sender) throws IOException {
in = new PipedReader(sender.getPipedWriter());
}
public void run() {
try {
while(true) {
// Blocks until characters are there:
System.out.println("Read: " + (char)in.read());
}
} catch(IOException e) {
throw new RuntimeException(e);
}
}
}
public class PipedIO {
public static void main(String[] args) throws Exception {
Sender sender = new Sender();
Receiver receiver = new Receiver(sender);
sender.start();
receiver.start();
new Timeout(4000, "Terminated");
}
} ///:~
Sender and Receiver represent threads that are performing some tasks and need to communicate with each other. Sender creates a PipedWriter, which is a standalone object, but inside Receiver the creation of PipedReader must be associated with a PipedWriter in the constructor. The Sender puts data into the Writer and sleeps for a random amount of time. However, Receiver has no sleep( ) or wait( ). But when it does a read( ), it automatically blocks when there is no more data. You get the effect of a producer-consumer, but no wait( ) loop is necessary.
Notice that the sender and receiver are started in main( ), after the objects are completely constructed. If you don’t start completely constructed objects, the pipe can produce inconsistent behavior on different platforms.