Java Forum / First Aid / February 2005
BufferedReader.readLine() hangs
dave.held@arrayservicesgrp.com - 31 Jan 2005 22:46 GMT The following program hangs on Linux 2.4.20, jre 1.5.0-01-b08, server VM with a suitably large input file (say, 4+ MB):
import java.io.BufferedReader; import java.io.FileReader;
public class ReadTest { public static void main(String[] args) { try { BufferedReader in = new BufferedReader(new FileReader(args[0])); in.readLine(); do { ReadTest.getRow(in); } while (in.ready()); } catch (Exception e) { e.printStackTrace(); } }
public static void getRow(BufferedReader in) throws Exception { int n = 0; while (in.ready()) { System.out.println(in.readLine()); if (++n > 10) return; } } }
It does not hang in the client VM. It does not hang if the readLine() call occurs in the outermost loop. It does not hang consistently. It does not always hang. But when it does hang, it appears to do so indefinitely. When it hangs, I can suspend the process, and when I resume it, the process continues normally to completion. Any idea what is going on?
Dave
klynn47@comcast.net - 01 Feb 2005 02:08 GMT What about replacing
public static void getRow(BufferedReader in) throws Exception { int n = 0; while (in.ready()) { System.out.println(in.readLine()); if (++n > 10) return;
} }
with
public static void getRow(BufferedReader in) throws Exception { for (int counter=0;counter<10;counter++) { String temp = in.readLine(); if (temp != null) System.out.println(temp); } }
toxa26@hotmail.com - 01 Feb 2005 02:58 GMT It doesnt actually hang. What happens is, InputStream.read() will block and wait for more data to arrive. If no data arrives, it'll just sit there. The reason it blocks sometimes and doesnt block other times is because BufferedReader.readLine() buffers a line till it gets to the first line temination character. If no line such character is sent by the server, InputStream.read() will block. If you have control over the data being sent to you, try making sure you are sending a \n at the end of the stream or do something like this:
StringBuffer buff = new StringBuffer(); int b; while( (b=is.read) != -1) { buff.append((char)b); }
and make sure -1 is sent at the end of the data stream. Hope this helps, Anton
David B. Held - 01 Feb 2005 14:35 GMT You must have missed the part where I am reading from a file. The file is a normal text file with lots of newlines in it. Reading *the same file*, it hangs at different points, depending on apparently unobservable factors. Sometimes it will read through the whole file without a pause.
Dave
Gordon Beaton - 01 Feb 2005 07:12 GMT > while (in.ready()); Others have already answered your question. I'd just like to point out that there is no need to call in.ready() before attempting to read, and that by doing so you risk either terminating the loop prematurely or failing to detect EOF altogether (and getting stuck there).
In general you should avoid using of BufferedReader.ready() and InputStream.available(), especially when you aren't trying to do anything else at the same time. Just read the data:
BufferedReader br = new BufferedReader(...); String line;
while ((line = br.readLine()) != null) { System.out.println(line); }
// now at end of file br.close();
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
David B. Held - 01 Feb 2005 14:50 GMT Others have answered my question, but they haven't solved the problem. I was suspicious about BufferedReader.ready(), but I don't have much experience with Java, and I inherited the code that originally called it. I changed my test code to eliminate calls to ready(), but it still hangs. Here is the revised version:
import java.io.BufferedReader; import java.io.FileReader;
public class ReadTest { public static void main(String[] args) { try { BufferedReader in = new BufferedReader(new FileReader(args[0])); while (ReadTest.getRow(in)); } catch (Exception e) { e.printStackTrace(); } }
public static boolean getRow(BufferedReader in) throws Exception { for (int i = 0; i != 10; ++i) { String s = in.readLine(); if (s == null) return false; System.out.println(s); } return true; } }
I'm testing it on a 3.8 MB file, but any suitably large file will do. Obviously, the contents shouldn't matter, but just in case someone thinks it does, I just captured the output of ps and appended the file to itself many times. I would appreciate it if someone else tried it on their server to see if they can reproduce the issue. Like I said, it only occurs with the server VM, so far as I can tell.
Dave
Gordon Beaton - 01 Feb 2005 16:32 GMT > Others have answered my question, but they haven't solved the > problem. I was suspicious about BufferedReader.ready(), but I don't > have much experience with Java, and I inherited the code that > originally called it. I changed my test code to eliminate calls to > ready(), but it still hangs. In that case I believe your problem lies elsewhere. Your code looks ok now and it works fine when I run it. It's currently about 1/3 of the way through a 178 MB text file, and I probably won't wait for it to finish.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
David B. Held - 01 Feb 2005 19:10 GMT Just out of curiosity, what platform are you using? In particular, are you running the code in the client or the server VM?
Dave
Gordon Beaton - 02 Feb 2005 07:37 GMT > Just out of curiosity, what platform are you using? In particular, > are you running the code in the client or the server VM? Since I haven't specified, I assume it's the client VM.
However I've never encountered (or even heard of) any problems specific to BufferedReader.readLine() on any JVM I've used since 1.1, which includes most JVMs from Sun, Blackdown and IBM on both Solaris and Linux.
This is what I tried (on Fedora 2):
java version "1.4.2_05" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_05-b04) Java HotSpot(TM) Client VM (build 1.4.2_05-b04, mixed mode)
java version "1.5.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64) Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Juha Laiho - 01 Feb 2005 16:15 GMT dave.held@arrayservicesgrp.com said:
>The following program hangs on Linux 2.4.20, jre 1.5.0-01-b08, >server VM with a suitably large input file (say, 4+ MB): ... Try getting a thread dump and see if it gives any indication where the code is executing at the time of hang. "kill -QUIT pid_of_java" should cause the thread dump to be printed.
 Signature Wolf a.k.a. Juha Laiho Espoo, Finland (GC 3.0) GIT d- s+: a C++ ULSH++++$ P++@ L+++ E- W+$@ N++ !K w !O !M V PS(+) PE Y+ PGP(+) t- 5 !X R !tv b+ !DI D G e+ h---- r+++ y++++ "...cancel my subscription to the resurrection!" (Jim Morrison)
David B. Held - 01 Feb 2005 19:09 GMT It looks like the JVM is trapping the signal because -QUIT doesn't do anything. ABRT did, but I got no thread dump. It's definitely in some kind of busy loop (and not blocking on an OS call) because it consumes CPU ticks even while hanging.
Dave
Gordon Beaton - 02 Feb 2005 14:59 GMT > It looks like the JVM is trapping the signal because -QUIT doesn't do > anything. ABRT did, but I got no thread dump. It's definitely in some > kind of busy loop (and not blocking on an OS call) because it consumes > CPU ticks even while hanging. You can use strace or ltrace to see (some of) what the process is up to.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
David B. Held - 08 Feb 2005 17:21 GMT > > It looks like the JVM is trapping the signal because -QUIT doesn't do > > anything. ABRT did, but I got no thread dump. It's definitely in some [quoted text clipped - 3 lines] > You can use strace or ltrace to see (some of) what the process is up > to. Very nice. Here's what I get:
------------------------------------------------------------------------------ [...thousands of lines snipped...] write(1, "root 6788 3389 0 22:00 ? "..., 53root 6788 3389 0 22:00 ? 00:00:00 CROND) = 53 write(1, "\n", 1 ) = 1 write(1, "root 6789 6788 0 22:00 ? "..., 80root 6789 6788 0 22:00 ? 00:00:00 /bin/bash -c /vendor/NCOA/result) = 80 write(1, "\n", 1 ) = 1 write(1, "smmsp 6796 6788 0 22:00 ? "..., 58smmsp 6796 6788 0 22:00 ? 00:00:00 [sendmail]) = 58 write(1, "\n", 1 ) = 1 gettimeofday({1107882934, 730151}, NULL) = 0 futex(0x810c94c, FUTEX_WAKE, 1) = 1 futex(0x82a28a4, FUTEX_WAIT, 4, NULL [1]+ Stopped strace java -server ReadTest test2.dat [root@xxxxxx xxxxxx]# fg strace java -server ReadTest test2.dat ) = -1 EINTR (Interrupted system call) futex(0x82a28a4, FUTEX_WAIT, 4, NULL <unfinished ...> [root@xxxxxx xxxxxx]# ------------------------------------------------------------------------------
So it was hanging on the futex(FUTEX_WAIT) call. I let it hang for a while, and then I interrupted it with a CTRL-Z. Then I brought it back to the foreground, and it insisted on continuing to wait. It probably would have waited indefinitely, but I did a CTRL-C which killed it. As I suspected, this appears to be a thread synchronization problem (a bug in the JVM?). However, any clues would be appreciated.
Dave
David B. Held - 08 Feb 2005 17:38 GMT > [...] > So it was hanging on the futex(FUTEX_WAIT) call. > [...] After Googling around, I found this gem:
http://evanjones.ca/java-linux.html
I consider it a must-read for anyone doing Java on RedHat.
Dave
Nigel Wade - 09 Feb 2005 10:26 GMT >> [...] >> So it was hanging on the futex(FUTEX_WAIT) call. [quoted text clipped - 7 lines] > > Dave It's not just Java which suffers from this. There are problems with the RedHat backport of FUTEX's into the 2.4 kernel. I've fought with it on SMP systems. It can be mitigated in some instances by removing the low-latency patch from the kernel.
 Signature Nigel Wade, System Administrator, Space Plasma Physics Group, University of Leicester, Leicester, LE1 7RH, UK E-mail : nmw@ion.le.ac.uk Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|