Java PipedOutputStream Class
Last modified: April 16, 2025
The java.io.PipedOutputStream
class is used to write data to a pipe
in a producer-consumer scenario. It must be connected to a PipedInputStream
to create a communication channel between threads. Data written to the output
stream can be read from the connected input stream.
PipedOutputStream
is typically used for inter-thread communication.
The pipe has a limited buffer size, and writes will block if the buffer is full.
Both ends of the pipe must be in the same process and typically in the same JVM.
PipedOutputStream Class Overview
PipedOutputStream
extends OutputStream
and provides
basic pipe writing functionality. Key methods include connecting to an input
stream, writing data, and closing the stream. The class is not thread-safe for
concurrent writes.
public class PipedOutputStream extends OutputStream { public PipedOutputStream(); public PipedOutputStream(PipedInputStream snk); public void connect(PipedInputStream snk); public void write(int b); public void write(byte[] b, int off, int len); public void flush(); public void close(); }
The code above shows key methods provided by PipedOutputStream
.
These methods allow writing data to the pipe and managing the connection. The
stream must be properly connected before writing data.
Creating a PipedOutputStream
PipedOutputStream can be created in two ways: with or without an existing
PipedInputStream
. If created without, it must be connected later.
The connection establishes the communication channel between threads.
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) { try { // Create unconnected output stream PipedOutputStream pos1 = new PipedOutputStream(); System.out.println("Created unconnected PipedOutputStream"); // Create and connect to existing input stream PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos2 = new PipedOutputStream(pis); System.out.println("Created connected PipedOutputStream"); pos1.close(); pos2.close(); pis.close(); } catch (IOException e) { e.printStackTrace(); } } }
This example demonstrates different ways to create PipedOutputStream. The first is unconnected and would need explicit connection later. The second is pre-connected to an existing PipedInputStream. Always close streams when done.
Connecting PipedOutputStream to PipedInputStream
The connection between output and input streams can be established either during creation or later using the connect method. Only one connection is allowed per stream. Attempting to reconnect throws an IOException.
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) { try { PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(); // Connect the streams pos.connect(pis); System.out.println("Streams connected successfully"); // Verify connection if (pis.available() == 0) { System.out.println("No data in pipe yet"); } pos.close(); pis.close(); } catch (IOException e) { e.printStackTrace(); } } }
This example shows how to connect PipedOutputStream to PipedInputStream after creation. The connection must be established before writing data. The available method checks if data is present in the input stream.
Writing Data to PipedOutputStream
Once connected, data can be written to the output stream and read from the input stream. Writes will block if the pipe buffer is full. The pipe has a default buffer size, but this can be specified when creating the input stream.
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) { try { PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis); // Write data to the output stream String message = "Hello from PipedOutputStream!"; pos.write(message.getBytes()); System.out.println("Data written to pipe"); // Read from input stream byte[] buffer = new byte[1024]; int bytesRead = pis.read(buffer); System.out.println("Read from pipe: " + new String(buffer, 0, bytesRead)); pos.close(); pis.close(); } catch (IOException e) { e.printStackTrace(); } } }
This example demonstrates writing data to PipedOutputStream and reading it from the connected PipedInputStream. The write method accepts byte arrays for bulk data transfer. The read operation blocks until data is available.
Inter-Thread Communication with Pipes
Piped streams are commonly used for communication between threads. One thread writes to the output stream while another reads from the input stream. This provides a thread-safe way to exchange data.
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) { try { PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis); // Writer thread Thread writer = new Thread(() -> { try { for (int i = 1; i <= 5; i++) { String msg = "Message " + i + "\n"; pos.write(msg.getBytes()); Thread.sleep(500); } pos.close(); } catch (Exception e) { e.printStackTrace(); } }); // Reader thread Thread reader = new Thread(() -> { try { int data; while ((data = pis.read()) != -1) { System.out.print((char) data); } pis.close(); } catch (IOException e) { e.printStackTrace(); } }); writer.start(); reader.start(); writer.join(); reader.join(); } catch (Exception e) { e.printStackTrace(); } } }
This example shows inter-thread communication using piped streams. The writer thread sends messages while the reader thread displays them. The pipe automatically handles synchronization between the threads.
Handling Large Data with PipedOutputStream
When dealing with large data, it's important to manage the pipe buffer size and coordinate between producer and consumer. The pipe has limited capacity, so the producer may block if the consumer isn't reading fast enough.
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) { try { // Create pipe with larger buffer (10KB) PipedInputStream pis = new PipedInputStream(10240); PipedOutputStream pos = new PipedOutputStream(pis); Thread producer = new Thread(() -> { try { byte[] data = new byte[4096]; for (int i = 0; i < 10; i++) { // Fill buffer with pattern for (int j = 0; j < data.length; j++) { data[j] = (byte) (i + j); } pos.write(data); System.out.println("Produced block " + i); } pos.close(); } catch (IOException e) { e.printStackTrace(); } }); Thread consumer = new Thread(() -> { try { byte[] buffer = new byte[1024]; int bytesRead; int total = 0; while ((bytesRead = pis.read(buffer)) != -1) { total += bytesRead; System.out.println("Consumed " + bytesRead + " bytes (total: " + total + ")"); } pis.close(); } catch (IOException e) { e.printStackTrace(); } }); producer.start(); consumer.start(); producer.join(); consumer.join(); } catch (Exception e) { e.printStackTrace(); } } }
This example demonstrates handling larger data volumes with a custom buffer size. The producer creates 4KB blocks while the consumer reads in 1KB chunks. The larger pipe buffer helps prevent blocking during data transfer.
Error Handling with PipedOutputStream
Proper error handling is crucial when working with piped streams. Common issues include broken pipes, connection failures, and interrupted threads. Always close streams in finally blocks or use try-with-resources.
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) { PipedInputStream pis = null; PipedOutputStream pos = null; try { pis = new PipedInputStream(); pos = new PipedOutputStream(); // Attempt to write before connecting try { pos.write("Test".getBytes()); } catch (IOException e) { System.out.println("Expected error: " + e.getMessage()); } // Connect properly pos.connect(pis); // Start reader thread Thread reader = new Thread(() -> { try { byte[] buffer = new byte[100]; int bytes = pis.read(buffer); System.out.println("Read: " + new String(buffer, 0, bytes)); } catch (IOException e) { System.out.println("Reader error: " + e.getMessage()); } }); reader.start(); // Write data pos.write("Successful communication".getBytes()); pos.flush(); reader.join(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (pos != null) pos.close(); if (pis != null) pis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
This example demonstrates proper error handling with piped streams. It shows what happens when writing to an unconnected pipe and includes proper cleanup in a finally block. The reader thread handles potential IOExceptions during reading.
Source
Java PipedOutputStream Class Documentation
In this article, we've covered the essential methods and features of the Java PipedOutputStream class. Understanding these concepts is crucial for working with inter-thread communication in Java applications.
Author
List all Java tutorials.