Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Piped Input stream is getting locked

Tags:

java

stream

I am trying to write the data using the pipe input streams. But from thread dump it looks like there is a lock on pipe input stream.

PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
FileInputStream fis = null;
GZIPOutputStream gos = null;
byte[] buffer = new byte[1024];
try {
    fis = new FileInputStream(file);
    gos = new GZIPOutputStream(pos);
    int length;
    while ((length = fis.read(buffer, 0, 1024)) != -1)
        gos.write(buffer, 0, length);
    } catch(Exception e){
        print("Could not read the file");
    }
    finally {
        try {
            fis.close();
            gos.close();
        }catch (Exception ie){ 
            printException(ie);
        }
    }
writeObject(pis);
pos.close();

writeobj method will simply read from the stream and but read method gets locked. The thread dumps indicate some wait on pipe input stream.

main" prio=10 tid=0x08066000 nid=0x48d2 in Object.wait() [0xb7fd2000..0xb7fd31e8]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0xa5c28be8> (a java.io.PipedInputStream)
    at java.io.PipedInputStream.awaitSpace(PipedInputStream.java:257)
    at java.io.PipedInputStream.receive(PipedInputStream.java:215)
    - locked <0xa5c28be8> (a java.io.PipedInputStream)
    at java.io.PipedOutputStream.write(PipedOutputStream.java:132)
    at java.util.zip.GZIPOutputStream.finish(GZIPOutputStream.java:95)
    at java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:146)

   Locked ownable synchronizers:
    - None

I am not really sure who is locking it up. Read docs to figure out the locking calls. But could not figure out what is going wrong and how to overcome it.

like image 394
Dheeraj Joshi Avatar asked Sep 06 '25 03:09

Dheeraj Joshi


2 Answers

Working with PipedInputStream and PipedOutputStream must be in separate threads.

Read the Javadoc carefully: http://docs.oracle.com/javase/6/docs/api/java/io/PipedInputStream.html

Typically, data is read from a PipedInputStream object by one thread and data is written to the corresponding PipedOutputStream by some other thread. Attempting to use both objects from a single thread is not recommended, as it may deadlock the thread.

like image 122
tilex Avatar answered Sep 08 '25 00:09

tilex


PipedInputStream has a small non-expanding buffer. Once the buffer is full, writes to the PipedOutputStream block until the buffered input is read by a different thread. You cannot use the two from the same thread, because the write will be waiting for a read that cannot happen.

In your case, you are not reading any of the data until you have written all of it, so the solution is to use a ByteArrayOutputStream and ByteArrayInputStream instead:

  1. Write all the data to a ByteArrayOutputStream.
  2. When finished, call toByteArray() on the stream to retrieve the byte data.
  3. (Optional) Create a ByteArrayInputStream with the byte data to read from it as an InputStream.
like image 23
Boann Avatar answered Sep 07 '25 22:09

Boann