Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.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 使用EntityUtils.consume(httpEntity)直到流结束的消费如何导致将连接释放回连接池?_Java_Connection Pooling_Httpconnection_Elasticsearch Rest Client - Fatal编程技术网

Java 使用EntityUtils.consume(httpEntity)直到流结束的消费如何导致将连接释放回连接池?

Java 使用EntityUtils.consume(httpEntity)直到流结束的消费如何导致将连接释放回连接池?,java,connection-pooling,httpconnection,elasticsearch-rest-client,Java,Connection Pooling,Httpconnection,Elasticsearch Rest Client,我读到EntityUtils.consume(httpEntity)将导致将连接释放回连接池,但当我查看源代码时,我无法理解这是如何发生的。有人能告诉我代码的哪一部分吗?EntityUtils.consume(httpEntity)或EntityUtils.toString(httpEntity)在我使用弹性搜索Rest客户端(org.elasticsearch.Client.RestClient-低级Rest客户端)时释放连接,如下: 如果存在SocketTimeoutException且我不

我读到
EntityUtils.consume(httpEntity)
将导致将连接释放回连接池,但当我查看源代码时,我无法理解这是如何发生的。有人能告诉我代码的哪一部分吗?
EntityUtils.consume(httpEntity)
EntityUtils.toString(httpEntity)
在我使用弹性搜索Rest客户端(org.elasticsearch.Client.RestClient-低级Rest客户端)时释放连接,如下:

如果存在SocketTimeoutException且我不使用HttpEntity,连接会发生什么情况?

客户端关闭并释放到池的连接(步骤)

  • EntityUtils.consume
    &
    EntityUtils.toString
    >第一个将
    关闭()。第二个将始终在其finally子句中调用
    instream.close()
    instream
    是为InputStream变量指定的名称

  • instream
    close()
    >在本例中,
    InputStream
    的实现是一个简单的过程。
    close()
    方法通过代码片段中显示的循环机制强制读取
    ContentInputStream
    ,直到其结束

    以下对此流的调用将导致异常

    @Override
    public void close() throws IOException 
    {
      final byte tmp[] = new byte[1024];
      /*loop until read() is -1, which means, advance the buffer till is end*/
      while (this.buffer.read(tmp, 0, tmp.length) >= 0) {}
      super.close();
    }
    
  • >检查所有池资源状态。此操作可能由某些操作触发(作为新请求),也可能由底层线程管理。如果一个资源/流被另一端关闭,它将获得一个
    EOF
    异常(因为缓冲区被迫前进到一端)。该点被标记为无效

  • >所有无效点均回收。它将删除已关闭的流并创建新的流,或恢复现有流,而无需擦除+创建(取决于资源类型)。这意味着保存流的点可以再次使用,新流可以使用:

    连接被释放回池。另一端不再使用它,因此池可以完全控制它。现在,允许池擦除、恢复并将其分配给其他请求者。


  • 示例

    让我们设想一个
    管理3种资源,例如
    HttpConnections
    。 你已经有3个线程在使用这个池,所以所有的点都被占用了

    同时
    ThreadZ
    等待将连接释放回池

    ThreadA
    已完成其作业并关闭其连接。当
    池条目的状态为关闭时,
    池将注意到这一点。不同的
    PoolEntry
    实现将以不同的方式检查这一点,其中一种方式是在尝试从流读取时获得
    EOF
    异常。其他实现可能有不同的机制来检查资源是否关闭。如果
    PoolEntry
    告知其资源已关闭/无效
    池将回收此点。这里有两个选项:

    a) 擦除并创建

    b) 恢复

    “重新释放连接”可以翻译为“现在又有了可用的地点/资源”。池现在可以连接到
    ThreadZ

     (spot1) [HttpConn1] -- ThreadZ
     (spot2) [HttpConn2] -- ThreadB
     (spot3) [HttpConn3] -- ThreadC
    

    消费
    /
    toString
    -连接释放

    上述所有说明意味着在
    输入流中调用
    close()
    将触发连接释放

    这发生在
    消费
    (如果实体内容已完全消费)和
    toString
    方法中:

    public static void consume(final HttpEntity entity) throws IOException 
    { 
        if (entity == null) 
            return; 
       
        if (entity.isStreaming()) 
        { 
            InputStream instream = entity.getContent(); 
            if (instream != null) 
                instream.close();   // <-- connection release
        } 
    } 
    
    public static String toString(final HttpEntity entity, final Charset defaultCharset) 
                                  throws IOException, ParseException 
    { 
        Args.notNull(entity, "Entity"); 
        InputStream instream = entity.getContent(); 
        if (instream == null) { 
            return null; 
        } 
        try { 
            Args.check(entity.getContentLength() <= Integer.MAX_VALUE,  
                    "HTTP entity too large to be buffered in memory"); 
            int i = (int)entity.getContentLength(); 
            if (i < 0) { 
                i = 4096; 
            } 
            Charset charset = null; 
            try { 
                ContentType contentType = ContentType.getOrDefault(entity); 
                charset = contentType.getCharset(); 
            } catch (UnsupportedCharsetException ex) { 
                throw new UnsupportedEncodingException(ex.getMessage()); 
            } 
            if (charset == null) { 
                charset = defaultCharset; 
            } 
            if (charset == null) { 
                charset = HTTP.DEF_CONTENT_CHARSET; 
            } 
            Reader reader = new InputStreamReader(instream, charset); 
            CharArrayBuffer buffer = new CharArrayBuffer(i); 
            char[] tmp = new char[1024]; 
            int l; 
            while((l = reader.read(tmp)) != -1) { 
                buffer.append(tmp, 0, l); 
            } 
            return buffer.toString(); 
        } finally { 
            instream.close();     // <--- connection release
        } 
    } 
    
    请注意,如果抛出
    SocketTimeoutException
    ,特定的
    PoolEntry
    实现也可以检查资源是否无效,而无需调用
    close()
    。使用
    close()

    @Override
    public void close() throws IOException 
    {
      final byte tmp[] = new byte[1024];
      /*loop until read() is -1, which means, advance the buffer till is end*/
      while (this.buffer.read(tmp, 0, tmp.length) >= 0) {}
      super.close();
    }
    
    但是特定的
    实现还可以检查资源是否无效,即使未被修补的
    异常
    不允许您专门调用
    close()
    ,因为它们可以使用不同的机制检查状态。例如,检查连接处于
    空闲状态的时间。如果此时间优于由
    池标记的某个treshold,则此点将被回收,而无需客户端先前的
    close()
    调用


    这一次,
    将是调用它的
    close()
    的终端,避免了客户端可能出现的
    死锁
    ,如果这个池不能管理最大连接时间或某些异常。

    谢谢,不过我应该在我的问题中更具体一些。我查看了instream.close(),如果我们以ContentInputStream或ByteArrayInputStream为例,close()代码的哪一部分触发了连接释放?InputStream.close()似乎什么也没做。释放的基本定义是基于池的性质。关闭意味着摧毁资源,因此现在只有一个点o
     (spot1) [HttpConn1] -- ThreadZ
     (spot2) [HttpConn2] -- ThreadB
     (spot3) [HttpConn3] -- ThreadC
    
    public static void consume(final HttpEntity entity) throws IOException 
    { 
        if (entity == null) 
            return; 
       
        if (entity.isStreaming()) 
        { 
            InputStream instream = entity.getContent(); 
            if (instream != null) 
                instream.close();   // <-- connection release
        } 
    } 
    
    public static String toString(final HttpEntity entity, final Charset defaultCharset) 
                                  throws IOException, ParseException 
    { 
        Args.notNull(entity, "Entity"); 
        InputStream instream = entity.getContent(); 
        if (instream == null) { 
            return null; 
        } 
        try { 
            Args.check(entity.getContentLength() <= Integer.MAX_VALUE,  
                    "HTTP entity too large to be buffered in memory"); 
            int i = (int)entity.getContentLength(); 
            if (i < 0) { 
                i = 4096; 
            } 
            Charset charset = null; 
            try { 
                ContentType contentType = ContentType.getOrDefault(entity); 
                charset = contentType.getCharset(); 
            } catch (UnsupportedCharsetException ex) { 
                throw new UnsupportedEncodingException(ex.getMessage()); 
            } 
            if (charset == null) { 
                charset = defaultCharset; 
            } 
            if (charset == null) { 
                charset = HTTP.DEF_CONTENT_CHARSET; 
            } 
            Reader reader = new InputStreamReader(instream, charset); 
            CharArrayBuffer buffer = new CharArrayBuffer(i); 
            char[] tmp = new char[1024]; 
            int l; 
            while((l = reader.read(tmp)) != -1) { 
                buffer.append(tmp, 0, l); 
            } 
            return buffer.toString(); 
        } finally { 
            instream.close();     // <--- connection release
        } 
    } 
    
    void tryConsume()
    {
       try 
       {
         //...
          EntityUtils.consume(httpEntity);
         //...
       }
       catch (IOException)
       {
         //SocketTimeoutException happened. Log the error,etc
         // (Close resources here...)
       }
       finally
       {
         //...Or maybe include a finally clause and close them here, if you wish 
         // them to be closed regardless of success/failure.
         if (httpEntity!=null)
         {
            InputStream instream = httpEntity.getContent(); 
            if (instream != null) 
                instream.close();   /* <-- connection release. when checking this 
                                     spot, the pool will get (f.e) an EOF 
                                     exception. This will lead to replacing this 
                                     resource with a fresh new connection and 
                                     setting the spot status as avaliable. */
          }
       }
    }