挂在IOUtils上的Java进程。疑似僵局

挂在IOUtils上的Java进程。疑似僵局,java,deadlock,openjdk,apache-commons-io,Java,Deadlock,Openjdk,Apache Commons Io,我有一个java进程挂起,调用IOUtils.toString,代码如下: String html = ""; try { html = IOUtils.toString(someUrl.openStream(), "utf-8"); // process hangs on this line } catch (Exception e) { return null; } 它无法可靠地复制这一点。它是web爬虫程序的一部分,因此成功地执行了数千次这一行,但最终导致进程在几天后挂起

我有一个java进程挂起,调用
IOUtils.toString
,代码如下:

String html = "";
try {
    html = IOUtils.toString(someUrl.openStream(), "utf-8"); // process hangs on this line
} catch (Exception e) {
    return null;
}
它无法可靠地复制这一点。它是web爬虫程序的一部分,因此成功地执行了数千次这一行,但最终导致进程在几天后挂起

输出自:

2013-09-2509:09:36
全线程转储OpenJDK 64位服务器VM(20.0-b12混合模式):
“附加侦听器”守护程序prio=10 tid=0x00007f2b1c01000 nid=0x225a等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“线程0”优先级=10 tid=0x00007f2b34122000 nid=0x187b可运行[0x00007f2b30970000]
java.lang.Thread.State:可运行
位于java.net.SocketInputStream.socketRead0(本机方法)
位于java.net.SocketInputStream.read(SocketInputStream.java:146)
在java.io.BufferedInputStream.fill处(BufferedInputStream.java:235)
位于java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
在java.io.BufferedInputStream.read处(BufferedInputStream.java:334)
-锁定(java.io.BufferedInputStream)
位于sun.net.www.http.ChunkedInputStream.readAheadBlocking(ChunkedInputStream.java:552)
位于sun.net.www.http.ChunkedInputStream.readAhead(ChunkedInputStream.java:609)
位于sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:696)
-锁定(sun.net.www.http.ChunkedInputStream)
在java.io.FilterInputStream.read(FilterInputStream.java:133)中
位于sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2582)
位于sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:282)
位于sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:324)
位于sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
-锁定(java.io.InputStreamReader)
位于java.io.InputStreamReader.read(InputStreamReader.java:184)
在java.io.Reader.read(Reader.java:140)
位于org.apache.commons.io.IOUtils.copyragle(IOUtils.java:1364)
位于org.apache.commons.io.IOUtils.copy(IOUtils.java:1340)
位于org.apache.commons.io.IOUtils.copy(IOUtils.java:1315)
位于org.apache.commons.io.IOUtils.toString(IOUtils.java:525)
我找不到任何方法来设置toString方法的超时。有什么建议吗?这是Apache commons中的一个bug吗?或者在我的OpenJDK中?

对toString()的调用最终被转发到。在这里,您可以看到从流中读取一直持续到InputStream.read()检测到文件结束(EOF)标记。根据read()可以读取0字节,即,如果您读取的URL连接没有返回EOF标记,则该方法可能会永远读取0字节

也许你可以找出哪个URL导致了这个问题


无论如何,要实现超时,您可以在一个单独的线程中开始每次读取,并在一段时间后终止该线程。

我决定尝试简单地使用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;
}
String html=”“;
试一试{
InputSupplierJava本机方法:

InputStream in=新URL(URL).openStream()

番石榴法:

输入供应商= Resources.newInputStreamSupplier(新URL(URL)); InputStream in=supplier.getInput()

它们都将抛出连接超时异常。因为guave也在使用URL.openStream()

但有些网站的速度太慢了,我每次都能从中读取一点数据,而且很多次还没有到达终点。我还看到它被Jstack挂在那里


像这样(可能只是在我的主机上运行缓慢):

我也遇到了同样的问题。也许它可以通过使用番石榴来解决,但在我看来,问题的根源是套接字没有配置soTimeout

试一试

socket.setSoTimeout(10000)


当10秒后没有EOF出现时抛出SocketTimeoutException。

可能是线程之间共享的“someUrl”?ioutils是开源的。附加一个调试器,暂停虚拟机,看看它被卡住了。啊,谢谢。我对哪个url引起的问题不太在意,但它可以帮助我设计一个可复制的测试。我正在尝试用番石榴作为替代品e因为它很简单,但如果失败了,那么我认为在单独的线程中运行它可能是我唯一的选择。感谢发布解决方案!我在2017年得到了这个解决方案,所以我想知道为什么这个问题仍然没有解决。。
String html = "";
try {
    InputSupplier<? extends InputStream> supplier = Resources
            .newInputStreamSupplier(metaUrl);
    html = CharStreams.toString(CharStreams.newReaderSupplier(supplier,
            Charsets.UTF_8));
} catch (Exception e) {
    return null;
}