我在使用以下代码调用IOUtils.toString
时挂起了一个java进程:
String html = "";
try {
html = IOUtils.toString(someUrl.openStream(), "utf-8"); // process hangs on this line
} catch (Exception e) {
return null;
}
无法可靠地重现这一点。它是网络爬虫的一部分,因此成功地执行了这一行数千次,但最终导致该过程在几天后挂起。
jstack的输出:
2013-09-25 09:09:36
Full thread dump OpenJDK 64-Bit Server VM (20.0-b12 mixed mode):
"Attach Listener" daemon prio=10 tid=0x00007f2b1c001000 nid=0x225a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-0" prio=10 tid=0x00007f2b34122000 nid=0x187b runnable [0x00007f2b30970000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:146)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
- locked <0x00000000e3d2d160> (a java.io.BufferedInputStream)
at sun.net.www.http.ChunkedInputStream.readAheadBlocking(ChunkedInputStream.java:552)
at sun.net.www.http.ChunkedInputStream.readAhead(ChunkedInputStream.java:609)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:696)
- locked <0x00000000e3d30558> (a sun.net.www.http.ChunkedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2582)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:282)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:324)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
- locked <0x00000000e3d317d0> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.Reader.read(Reader.java:140)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1364)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1340)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1315)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:525)
我看不到在toString方法上设置超时的任何方法。有什么建议?这是Apache公共中的错误吗?或者也许在我的OpenJDK中?
答案 0 :(得分:2)
您对toString()的调用最终会转发到copyLarge()。在这里,您可以看到继续从流中读取,直到InputStream.read()检测到文件结束(EOF)标记。根据{{3}},read()可以读取0个字节,即如果你读取的URLConnection没有返回EOF标记,则该方法可能会永远读取0个字节。
也许您可以追踪导致问题的网址?
无论如何,要实现超时,你可以在一个单独的线程中开始每次读取,并在经过一段时间后终止该线程。
答案 1 :(得分:1)
我决定尝试简单地使用guava IO,因为它已经在我的类路径中了:
String html = "";
try {
InputSupplier<? extends InputStream> supplier = Resources
.newInputStreamSupplier(metaUrl);
html = CharStreams.toString(CharStreams.newReaderSupplier(supplier,
Charsets.UTF_8));
} catch (Exception e) {
return null;
}
通常需要几天时间才能崩溃,所以如果我在几天内没有更新这个答案,那么假设这有效!
更新:到目前为止7天没有挂......:)
答案 2 :(得分:1)
我遇到了同样的问题。也许它通过使用番石榴来解决,但在我看来问题的根源是套接字没有配置soTimeout。
试
socket.setSoTimeout(10000)
在10秒后没有EOF时抛出SocketTimeoutException。
答案 3 :(得分:0)
Java原生方法:
InputStream in = new URL(url).openStream();
番石榴方法:
InputSupplier供应商= Resources.newInputStreamSupplier(new URL(url)); InputStream in = supplier.getInput();
它们都会抛出Connection超时异常。因为guave也使用URL.openStream()
但有些网站速度很慢,我每次都可以从中读取一些数据,而且很多次仍未达到目的。我也看到它被Jstack挂在那里。
像这样(可能只在主持人身上很慢):a txt file address