Piped OutputStream and Pipedlnput Stream

Threads often need to communicate. One communication approach involves using shared variables. Another approach involves using piped streams courtesy of Java's PipedOutputStream and PipedlnputStream classes.

The concrete PipedOutputStream class lets a sending thread write a stream of bytes to an instance of the concrete PipedlnputStream class, which a receiving thread uses to subsequently read those bytes.

CAUTION: Attempting to use a PipedOutputStream object and a PipedInputStream object from a single thread is not recommended because it may deadlock the thread.

PipedOutputStream declares a pair of constructors for creating piped output streams:

■ PipedOutputStream() creates a piped output stream that is not yet connected to a piped input stream. It must be connected to a piped input stream, either by the receiver or the sender, before being used.

■ PipedOutputStream(PipedInputStream dest) creates a piped output stream that is connected to piped input stream dest. Bytes written to the piped output stream can be read from dest. This constructor throws IOException when an I/O error occurs.

PipedOutputStream declares a void connect(PipedInputStream dest) method that connects this piped output stream to dest. This method throws IOException when this piped output stream is already connected to another piped input stream.

PipedInputStream declares four constructors for creating piped input streams:

■ PipedInputStream() creates a piped input stream that is not yet connected to a piped output stream. It must be connected to a piped output stream before being used.

■ PipedInputStream(int pipeSize) creates a piped input stream that is not yet connected to a piped output stream and uses pipeSize to size the piped input stream's buffer. It must be connected to a piped output stream before being used. This constructor throws IllegalArgumentException when pipeSize is less than or equal to 0.

■ PipedInputStream(PipedOutputStream src) creates a piped input stream that is connected to piped output stream src. Bytes written to src can be read from this piped input stream. This constructor throws IOException when an I/O error occurs.

■ PipedInputStream(PipedOutputStream src, int pipeSize) creates a piped input stream that is connected to piped output stream src and uses pipeSize to size the piped input stream's buffer. Bytes written to src can be read from this piped input stream. This constructor throws IOException when an I/O error occurs, and IllegalArgumentException when pipeSize is less than or equal to 0.

PipedInputStream declares a void connect(PipedInputStream src) method that connects this piped input stream to src. This method throws IOException when this piped input stream is already connected to another piped output stream.

The easiest way to create a pair of piped streams is in the same thread, and in either order. For example, you can first create the piped output stream:

PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos);

Alternatively, you can first create the piped input stream:

PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis);

You can leave both streams unconnected and later connect them to each other using the appropriate piped stream's connect() method, as follows:

PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(); // ...

pos.connect(pis);

Listing 10-11 presents a PipedStreamsDemo application whose sender thread streams a sequence of randomly generated byte integers to a receiver thread, which outputs this sequence.

Listing 10-11. Piping randomly generated bytes from a sender thread to a receiver thread import java.io.IOException; import java.io.PipedOutputStream; import java.io.PipedInputStream;

public class PipedStreamsDemo {

public static void main(String[] args) throws IOException {

final PipedOutputStream pos = new PipedOutputStream(); final PipedInputStream pis = new PipedInputStream(pos);

Runnable senderTask = new Runnable() {

final static int LIMIT = 10;

catch (IOException ioe) {

ioe.printStackTrace();

finally {

catch (IOException ioe) {

ioe.printStackTrace();

Runnable receiverTask = new Runnable() {

while ((b = pis.read()) != -1) System.out.println(b);

catch (IOException ioe) {

ioe.printStackTrace();

finally {

catch (IOException ioe) {

ioe.printStackTrace();

Thread sender = new Thread(senderTask); Thread receiver = new Thread(receiverTask); sender.start(); receiver.start();

When you run this application, you will discover output similar to the following:

138 143 130

Perhaps you are wondering why I did not also declare pos and pis volatile? After all, each variable is accessed by the main thread and its sender or receiver thread. I did not declare these variables volatile for the following reasons:

■ The compiler outputs a "modifier volatile not allowed here" error message whenever you attempt to declare a local variable volatile (only fields can be declared volatile).

■ The compiler outputs an "illegal combination of modifiers: final and volatile" error message whenever you combine final with volatile in a field declaration (final fields are immutable; they are not volatile).

Was this article helpful?

0 0

Post a comment