Why BufferedReader.read(char[], int, int) blocks?

V

vg

Hi!

I'm reading data from a socket (an HTTP request) using a
BufferedReader. The read(char[], int, int) method blocks even though
data is available (i'm testing locally). My question is why it blocks
since the javadocs say this method should never block! Or I'm missing
something here?

I'm using jdk1.4.1 on Windows 2000.

Thank you for your time!
VG
 
G

Gordon Beaton

I'm reading data from a socket (an HTTP request) using a
BufferedReader. The read(char[], int, int) method blocks even though
data is available (i'm testing locally). My question is why it
blocks since the javadocs say this method should never block! Or I'm
missing something here?

If read() blocks, I would say it's because data *isn't* available.
What makes you think that isn't the case? How are you making the
observation?

Post the relevant parts of your code.

/gordon
 
J

John C. Bollinger

vg said:
I'm reading data from a socket (an HTTP request) using a
BufferedReader. The read(char[], int, int) method blocks even though
data is available (i'm testing locally).

Testing locally does not necessarilly mean that data is always available
without blocking. How do you know that the method blocks, or
alternatively, how do you know that data is available?
My question is why it blocks
since the javadocs say this method should never block! Or I'm missing
something here?

Well, you're at least adding something to what is actually in the docs,
which do _not_ say that the method never blocks. The docs appear to say
that it will not block if there is at least one character available or
at the end of the stream, but that otherwise it will.
 
V

vg

John C. Bollinger said:
vg said:
I'm reading data from a socket (an HTTP request) using a
BufferedReader. The read(char[], int, int) method blocks even though
data is available (i'm testing locally).

Testing locally does not necessarilly mean that data is always available
without blocking. How do you know that the method blocks, or
alternatively, how do you know that data is available?

When I run my app normally, it hungs immediately after submiting data
to the server. Debuging revealed that the read() method was the source
of blocking. I admit I cannot be 100% sure that the data is really
available but I was testing with less than 10kB of data sent from a
locally opened browser to my locally runing server.
Well, you're at least adding something to what is actually in the docs,
which do _not_ say that the method never blocks. The docs appear to say
that it will not block if there is at least one character available or
at the end of the stream, but that otherwise it will.

Please, Sir, read the javadoc from the BufferedReader.read() method! I
quote:
<<This iterated read continues until one of the following conditions
becomes true:
· The specified number of characters have been read,
· The read method of the underlying stream returns -1, indicating
end-of-file, or
· The ready method of the underlying stream returns false, indicating
that further input requests would block. >>

Therefore, this method always (should) abort the reading when the
stream is drained! They say it checks the ready() method of the
underlying stream...

This is my code, where len initally holds the total number of bytes I
have to read:

pos = 0;
char b[] = new char[len];
while (len > 0) {
if ((dim = reader.read(b, pos, len)) != -1) {
len -= dim;
pos += dim;
}
}
 
R

Rogan Dawes

vg said:
John C. Bollinger said:
vg wrote:

I'm reading data from a socket (an HTTP request) using a
BufferedReader. The read(char[], int, int) method blocks even though
data is available (i'm testing locally).

Testing locally does not necessarilly mean that data is always available
without blocking. How do you know that the method blocks, or
alternatively, how do you know that data is available?


When I run my app normally, it hungs immediately after submiting data
to the server. Debuging revealed that the read() method was the source
of blocking. I admit I cannot be 100% sure that the data is really
available but I was testing with less than 10kB of data sent from a
locally opened browser to my locally runing server.

Well, you're at least adding something to what is actually in the docs,
which do _not_ say that the method never blocks. The docs appear to say
that it will not block if there is at least one character available or
at the end of the stream, but that otherwise it will.


Please, Sir, read the javadoc from the BufferedReader.read() method! I
quote:
<<This iterated read continues until one of the following conditions
becomes true:
· The specified number of characters have been read,
· The read method of the underlying stream returns -1, indicating
end-of-file, or
· The ready method of the underlying stream returns false, indicating
that further input requests would block. >>

Therefore, this method always (should) abort the reading when the
stream is drained! They say it checks the ready() method of the
underlying stream...

This is my code, where len initally holds the total number of bytes I
have to read:

pos = 0;
char b[] = new char[len];
while (len > 0) {
if ((dim = reader.read(b, pos, len)) != -1) {
len -= dim;
pos += dim;
}
}

Two things:

Firstly, BufferedReader calls Reader.read(char[], int, int) which can
block. I read the docs to say that once the first read has returned, it
will attempt to keep reading any additional available characters, so
long as the conditions above are true.

Also, your loop termination clause may be flawed:

If the read returns -1 (i.e. end of stream), you will end up in a
spinloop trying to read from a closed stream, and getting -1 every time,
never decrementing len, and never exiting the while loop.

I suggest that you terminate the while loop if dim == -1, and check to
see if (len>0) when you have exited the while.

e.g.:

pos=0;
char b[] = new char[len];
int dim = 0;
while ((dim = reader.read(b, pos, b.length - pos)) > -1) {
pos += dim;
}
if (pos < b.length) {
System.err.println("Failed to read all the data, got " + pos +
" of " + b.length + " characters");
}

Note the side effect that len is not changed to be "0" at the end of
this loop, which may be relevant in your code.

Regards,

Rogan
 
M

Michael Borgwardt

Rogan said:
Firstly, BufferedReader calls Reader.read(char[], int, int) which can
block. I read the docs to say that once the first read has returned, it
will attempt to keep reading any additional available characters, so
long as the conditions above are true.

A look at the source code confirms this interpretation: ready() is
*not* checked before the first read() call.
 
J

John C. Bollinger

Michael said:
Rogan said:
Firstly, BufferedReader calls Reader.read(char[], int, int) which can
block. I read the docs to say that once the first read has returned,
it will attempt to keep reading any additional available characters,
so long as the conditions above are true.


A look at the source code confirms this interpretation: ready() is
*not* checked before the first read() call.

And it must not be, because at least one character is guaranteed to be
read, except at the end of the stream.


John Bollinger
(e-mail address removed)
 
V

vg

Thank you Sir for your advices!

Yes, you're right and my code can be improved and I will. I also
observe that inside the BufferedReader.read() method, there is a
potentially blocking call to java.io.Reader.read(). Anyway, I still
believe the javadoc of BufferedReader.read() should warn you about
this potential block read.

Again, thank you all for your time!
Best regards,
VG.
vg said:
John C. Bollinger said:
vg wrote:


I'm reading data from a socket (an HTTP request) using a
BufferedReader. The read(char[], int, int) method blocks even though
data is available (i'm testing locally).

Testing locally does not necessarilly mean that data is always available
without blocking. How do you know that the method blocks, or
alternatively, how do you know that data is available?


When I run my app normally, it hungs immediately after submiting data
to the server. Debuging revealed that the read() method was the source
of blocking. I admit I cannot be 100% sure that the data is really
available but I was testing with less than 10kB of data sent from a
locally opened browser to my locally runing server.

My question is why it blocks
since the javadocs say this method should never block! Or I'm missing
something here?

Well, you're at least adding something to what is actually in the docs,
which do _not_ say that the method never blocks. The docs appear to say
that it will not block if there is at least one character available or
at the end of the stream, but that otherwise it will.


Please, Sir, read the javadoc from the BufferedReader.read() method! I
quote:
<<This iterated read continues until one of the following conditions
becomes true:
· The specified number of characters have been read,
· The read method of the underlying stream returns -1, indicating
end-of-file, or
· The ready method of the underlying stream returns false, indicating
that further input requests would block. >>

Therefore, this method always (should) abort the reading when the
stream is drained! They say it checks the ready() method of the
underlying stream...

This is my code, where len initally holds the total number of bytes I
have to read:

pos = 0;
char b[] = new char[len];
while (len > 0) {
if ((dim = reader.read(b, pos, len)) != -1) {
len -= dim;
pos += dim;
}
}

Two things:

Firstly, BufferedReader calls Reader.read(char[], int, int) which can
block. I read the docs to say that once the first read has returned, it
will attempt to keep reading any additional available characters, so
long as the conditions above are true.

Also, your loop termination clause may be flawed:

If the read returns -1 (i.e. end of stream), you will end up in a
spinloop trying to read from a closed stream, and getting -1 every time,
never decrementing len, and never exiting the while loop.

I suggest that you terminate the while loop if dim == -1, and check to
see if (len>0) when you have exited the while.

e.g.:

pos=0;
char b[] = new char[len];
int dim = 0;
while ((dim = reader.read(b, pos, b.length - pos)) > -1) {
pos += dim;
}
if (pos < b.length) {
System.err.println("Failed to read all the data, got " + pos +
" of " + b.length + " characters");
}

Note the side effect that len is not changed to be "0" at the end of
this loop, which may be relevant in your code.

Regards,

Rogan
 
J

John C. Bollinger

vg said:
I also
observe that inside the BufferedReader.read() method, there is a
potentially blocking call to java.io.Reader.read(). Anyway, I still
believe the javadoc of BufferedReader.read() should warn you about
this potential block read.

You continue to miss the point. The BufferedReader class nowhere
promises that the method will not block, contrary to your previous
assertions. As I wrote before, you read that in when it is not there.
On the other hand, the superclass promises that the method _will_ block
under certain circumstances, which is exactly the documentation you
wanted. The subclass' contract for that method is consistent with the
superclass', as you should expect.

It would be convenient, but IMO not feasible, for every method in the
platform API to be documented with its full contract, including details
documented in all superclasses. The HTML API docs give you easy access
to the docs for overridden methods, which is about the best practical
mechanism I can see.


John Bollinger
(e-mail address removed)
 
N

Nigel Wade

vg said:
Thank you Sir for your advices!

Yes, you're right and my code can be improved and I will. I also
observe that inside the BufferedReader.read() method, there is a
potentially blocking call to java.io.Reader.read(). Anyway, I still
believe the javadoc of BufferedReader.read() should warn you about
this potential block read.

Again, thank you all for your time!
Best regards,
VG.

It very clearly tells you.

It states " This method implements the general contract of the corresponding
read method of the Reader class". If you don't read what that contract is
(and it's hyperlinked in Javadoc to make it easy), that's your fault, not
the fault of the documentation.
 
A

Andrew Thompson

vg wrote: ...

It very clearly tells you.
<snip advice re RTFM>

Good advice Nigel.

It would have been even better if
you'd trimmed a bit and paid more
attention to attributions.

[ In this instance you listed Rogan
at the top, yet did not quote any of
his comments - which can be confusing. ]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top