Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HttpURLConnection InputStream.close()挂起(或工作时间过长?)_Java_Http_Tcp_Httpurlconnection - Fatal编程技术网

Java HttpURLConnection InputStream.close()挂起(或工作时间过长?)

Java HttpURLConnection InputStream.close()挂起(或工作时间过长?),java,http,tcp,httpurlconnection,Java,Http,Tcp,Httpurlconnection,首先,一些背景。有一个工作程序可以扩展/解析一堆短URL: http://t.co/example -> http://example.com 所以,我们只需遵循重定向。就这样。我们不从连接中读取任何数据。在我们得到200之后,我们返回最终的URL并关闭InputStream 现在是问题本身。在生产服务器上,InputStream.close()调用中挂起了一个解析器线程。调用: "ProcessShortUrlTask" prio=10 tid=0x00007f8810119000 n

首先,一些背景。有一个工作程序可以扩展/解析一堆短URL:

http://t.co/example -> http://example.com
所以,我们只需遵循重定向。就这样。我们不从连接中读取任何数据。在我们得到200之后,我们返回最终的URL并关闭InputStream

现在是问题本身。在生产服务器上,
InputStream.close()调用中挂起了一个解析器线程。
调用:

"ProcessShortUrlTask" prio=10 tid=0x00007f8810119000 nid=0x402b runnable [0x00007f882b044000]
   java.lang.Thread.State: RUNNABLE
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
        at java.io.BufferedInputStream.skip(BufferedInputStream.java:352)
        - locked <0x0000000561293aa0> (a java.io.BufferedInputStream)
        at sun.net.www.MeteredStream.skip(MeteredStream.java:134)
        - locked <0x0000000561293a70> (a sun.net.www.http.KeepAliveStream)
        at sun.net.www.http.KeepAliveStream.close(KeepAliveStream.java:76)
        at java.io.FilterInputStream.close(FilterInputStream.java:155)
        at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.close(HttpURLConnection.java:2735)
        at ru.twitter.times.http.URLProcessor.resolve(URLProcessor.java:131)
        at ru.twitter.times.http.URLProcessor.resolve(URLProcessor.java:55)
        at ...
在我看来,JDK本身似乎有一个bug。不幸的是,很难重现这个…

我想
close()
上的
skip()
是为了保持活动支持

在JavaSE6之前,如果应用程序在 还有一小部分数据需要读取,然后 连接必须关闭,而不是缓存。现在在JavaSE中 6,其行为是在一个内存中读取最多512 KB的连接 后台线程,从而允许重新使用连接。这个 可读取的确切数据量可通过
http.KeepAlive.remainingData
system属性

因此,可以使用
http.KeepAlive.remainingData=0
http.KeepAlive=false
有效禁用keep alive。 但是,如果总是寻址到同一个主机,这可能会对性能产生负面影响


正如@artbristol所建议的,在这里使用HEAD而不是GET似乎是更好的解决方案。

您链接的
KeepAliveStream
的实现违反了合同,根据该合同,
available()
skip()
保证是非阻塞的,因此可能确实是阻塞的

保证单个无阻塞skip():

返回可读取字节数的估计值(或 跳过)而不会被下一个 此输入流的方法的调用方。下一个来电者可能是 同一条线或另一条线。一次读取或跳过此文件 许多字节不会阻塞,但可以读取或跳过更少的字节

其中,实现每次调用
available()
多次调用
skip()


if(nskip我在尝试发出“HEAD”请求时遇到了类似的问题。为了解决这个问题,我删除了“HEAD”方法,因为我只想ping url

您是否尝试过直接使用InputStream而不是BufferedInputStream?流是从HttpURLConnection返回的。getInputStream()呼叫。我无法控制它。我明白了。好吧,这只是一个意外。你能用
HEAD
而不是
GET
?是的,在某些情况下,我们可以使用HEAD作为非常好的优化。不,我们不能完全摆脱GET。原因有两个。首先,不是每个网站都支持HEAD。其次,我们需要尽可能多地模拟浏览器行为。Even如果某个站点支持HEAD,它可能返回与GET不同的内容。感谢您指向
remainingData
选项。很高兴知道。虽然问题没有解决。而且,我完全不明白为什么
close()
挂起。文档说明:在后台线程中读取高达512 KB的数据。即使站点速度太慢,无法在两天内为我们提供512 KB的数据,“后台”线程如何挂起应用程序?是的,我们不想完全禁用连接缓存(我们知道
keepAlive=false
和其他一些允许关闭它的缓存设置)。另请参阅我对@artbristol关于HEAD的评论。谢谢你,Jan。事实上,这是一个非常合理的解释。你知道JDK开发社区中是否有反向移植的做法吗?有没有可能在JDK6/7中修复此问题?@Shcheklein根据本网站的信息,Java SE版本会更新错误修复、安全修复和针对或者至少3年的期限…’。对于Java 6,这一期限将于2013年2月结束,但Java 7应在2014年7月之前接受错误修复。我不清楚这一特定修复是否为市场v8,也许它被认为优先级太低(P4)。如果您对该错误发表评论并解释它是在实际应用程序中遇到的,以及他们是否计划修复v7,可能会有所帮助,因为根据他们应该执行的策略。您显示的代码在close()中,close()的约定不保证非阻塞。
    // Skip past the data that's left in the Inputstream because
    // some sort of error may have occurred.
    // Do this ONLY if the skip won't block. The stream may have
    // been closed at the beginning of a big file and we don't want
    // to hang around for nothing. So if we can't skip without blocking
    // we just close the socket and, therefore, terminate the keepAlive
    // NOTE: Don't close super class
    try {
        if (expected > count) {
        long nskip = (long) (expected - count);
        if (nskip <= available()) {
            long n = 0;
            while (n < nskip) {
            nskip = nskip - n;
            n = skip(nskip);} ...
    if (nskip <= available()) {
        long n = 0;
        // The loop below can iterate several times,
        // only the first call is guaranteed to be non-blocking. 
        while (n < nskip) { 
        nskip = nskip - n;
        n = skip(nskip);
        }