2013-09-25 55 views
3

我有一個掛在調用IOUtils.toString用下面的代碼Java進程:掛在IOUtils上的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

可能是'someUrl'在線程之間共享? –

+0

ioutils是開源的。附上一個調試器,暫停虛擬機並查看它卡住的位置。 –

回答

1

我決定嘗試用簡單的番石榴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天至今沒有掛... :)

+0

感謝您發佈解決方案!我在2017年得到這個,所以我想知道爲什麼這仍然沒有解決.. – tObi

2

您對toString()的調用最終被轉發到copyLarge()。在這裏您可以看到從流中讀取數據的過程一直持續到InputStream.read()檢測到文件結尾(EOF)標記爲止。根據this post read()可以讀取0個字節,也就是說,如果您讀取的URLConnection不返回EOF標記,則該方法可能會永遠讀取0個字節。

也許你可以追蹤哪個URL導致問題?

無論如何,要實現超時,您可以在單獨的線程中開始每個讀取操作,並在特定時間過後殺死該線程。

+0

啊,謝謝。我不是那個造成它的網址的人,但它可以幫助我設計一個可重複的測試。我試圖用番石榴作爲替代品,因爲它很簡單,但如果失敗了,那麼我認爲在單獨的線程中運行它可能是我唯一的選擇。 –

0

Java本機方法:在=新的網址(URL)

的InputStream .openStream();

番石榴方法:

InputSupplier供應商= Resources.newInputStreamSupplier(新的URL(URL)); InputStream in = supplier.getInput();

兩者都會拋出Connection超時異常。因爲guave也是使用URL.openStream()

但是有些網站太慢了,我可以每次從它讀取一點數據,而這麼多次還是沒有達到目的。而且我也看到它被Jstack掛在那裏。

這樣的(也許只有在我的主機慢):a txt file address

1

我有同樣的問題。也許它通過使用番石榴來解決,但在我看來,問題的根源在於套接字沒有配置soTimeout。

嘗試

socket.setSoTimeout(10000)

拋出SocketTimeoutException當沒有EOF 10秒後到來。