Question

I'm trying to write code that reads from a Reader in a non-blocking way, i.e. only calling read() after ensuring ready() returns true.

To test the code, I use the PipedReader/PipedWriter combo, and ready() works great, until I close the PipedWriter, which also marks the end of the stream on the side of PipedReader. However, although its ready() method will never again return true, read() instantly returns -1 when called.

In this case, is there a non-blocking way to figure out that a call to read() would not block?

Here's an example that reproduces the issue.

package test;

import java.io.*;

public class Piper
{
    public static void main(String[] args) throws Exception
    {
        int sleepBetweenChars = 100;
        boolean throttle = true;
        Reader reader = new StringReader("abc");
        if (throttle)
            reader = throttle(sleepBetweenChars, reader);
        while (true)
        {
            if (reader.ready())
            {
                int c = reader.read();
                System.out.println("Read " + c);
                if (c == -1)
                    break;
            }
            else
            {
                System.out.println("Not ready");
                Thread.sleep(sleepBetweenChars);
                if (!reader.ready())
                {
                    System.out.println("Still not ready, sleep some more");
                    Thread.sleep(20 * sleepBetweenChars);
                    if (!reader.ready())
                    {
                        int c = reader.read();
                        System.out.println("Still not ready, we read nonetheless: " + c);
                        if (c == -1)
                            break;
                    }
                }
            }
        }
    }
    private static Reader throttle(final int sleepBetweenChars, final Reader in) throws IOException
    {
        final PipedWriter pw = new PipedWriter();
        PipedReader pr = new PipedReader(pw);
        (new Thread(new Runnable()
        {
            public void run()
            {
                System.out.println("Start piping");
                int c;
                try
                {
                    while ((c = in.read()) != -1)
                    {
                        pw.write(c);
                        Thread.sleep(sleepBetweenChars);
                    }
                    pw.close();
                    System.out.println("Closed PipedWriter");
                }
                catch (Throwable t)
                {
                    t.printStackTrace();
                }
            }
        })).start();
        return pr;
    }
}
Was it helpful?

Solution

PipedReader never ready() at end of stream

I agree. That's not what it's for. ready() tells you whether there is data available to be read, not end-of-file conditions. See the Javadoc: ' A piped character stream is ready if the circular buffer is not empty'.

There isn't a way to do what you're trying to do. Streams and Readers are irredemiably blocking. Your code is basically just an elaborate way of implementing blocking yourself, with added latency and added bugs. It's pointless.

I would also question your use of piped readers and writers at all. They are singularly useless things, really only a proof-of-concept for wait() and notify(). Possibly what you're really looking for is a Queue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top