线程被阻止何时重用apache httpclient

时间:2014-07-23 07:27:13

标签: java httpclient

我使用apache httpclient 4.3.4,我想在工作线程中重用httpclient实例,但是当httpclient第二次发布数据时线程被阻塞。

class SinglePostConnectionThread extends Thread {
    void processResponse(CloseableHttpResponse response) throws Exception{
      try{
          StatusLine sLine = response.getStatusLine();
          switch (sLine.getStatusCode()){
            case 200:{
              break;
            }
            case 204:{
              //HttpEntity entity = response.getEntity();
              //entity.getContent().close();
              System.out.println("No Flight");
              break;
            }
            default:
              System.out.println("Bad response");
          }
        } catch (Exception e){
          System.out.println(e.getMessage());
        }finally {
          System.out.println("Close response");
          response.close();
      }

    }
    @Override
    public void run() {
      BasicHttpClientConnectionManager basicConnManager =    new BasicHttpClientConnectionManager();
      HttpClientContext context = HttpClientContext.create();

      try {

        CloseableHttpClient client = HttpClients.custom().setConnectionManager(basicConnManager).build();
        int tmpLoop = loopNum;
        while (tmpLoop > 0) {
          HttpPost post = new HttpPost(host);
        StringEntity se = new StringEntity(toJson(bid), "utf-8");
        post.setHeader(HTTP.CONTENT_TYPE, "application/json");
        post.setEntity(se);
          processResponse(client.execute(post, context));//blocked when running at second time
          tmpLoop--;
          if (loopNum ==0){
            tmpLoop = 1;
          }
          post.releaseConnection();
          //basicConnManager.;
        }
      } catch (Exception e){
        e.printStackTrace();
      }
    }
  }

似乎连接已用完,但我实际上关闭了所有资源。

1 个答案:

答案 0 :(得分:5)

您不能在多线程环境中使用简单连接管理器,即使此类是线程安全的,也只能由一个执行线程使用。

Apache HTTP Components tutorial

中提取
  

<强> 2.3.2。简单连接管理器

     

BasicHttpClientConnectionManager是一个简单的连接管理器   一次只维护一个连接。即使这个班级是   线程安全它应该只由一个执行线程使用。   BasicHttpClientConnectionManager将努力重用   使用相同路由的后续请求的连接。它会,   但是,关闭现有连接并为给定连接重新打开它   route,如果持久连接的路由不匹配   连接请求。如果连接已经存在   allocate,然后抛出java.lang.IllegalStateException。

所以,您使用了池连接管理器

  

<强> 2.3.3。池化连接管理器

     

PoolingHttpClientConnectionManager是一个更复杂的实现   管理客户端连接池并且能够提供服务   来自多个执行线程的连接请求。连接是   按路线汇总。要求获得的路线   manager已经在池中提供了持久连接   通过租用池中的连接而不是创建来提供服务   一个全新的联系。

     

PoolingHttpClientConnectionManager保持最大限制   基于每条路线和总共的连接。默认为此   实现将创建不超过2个并发连接   给定路线,总共不再有20个连接。对于许多现实世界   应用这些限制可能会受到限制,特别是如果   他们使用HTTP作为其服务的传输协议。

您可以查看Threaded request execution示例

package org.apache.http.examples.client;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

/**
 * An example that performs GETs from multiple threads.
 *
 */
public class ClientMultiThreadedExecution {

    public static void main(String[] args) throws Exception {
        // Create an HttpClient with the ThreadSafeClientConnManager.
        // This connection manager must be used if more than one thread will
        // be using the HttpClient.
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100);

        CloseableHttpClient httpclient = HttpClients.custom()
                .setConnectionManager(cm)
                .build();
        try {
            // create an array of URIs to perform GETs on
            String[] urisToGet = {
                "http://hc.apache.org/",
                "http://hc.apache.org/httpcomponents-core-ga/",
                "http://hc.apache.org/httpcomponents-client-ga/",
            };

            // create a thread for each URI
            GetThread[] threads = new GetThread[urisToGet.length];
            for (int i = 0; i < threads.length; i++) {
                HttpGet httpget = new HttpGet(urisToGet[i]);
                threads[i] = new GetThread(httpclient, httpget, i + 1);
            }

            // start the threads
            for (int j = 0; j < threads.length; j++) {
                threads[j].start();
            }

            // join the threads
            for (int j = 0; j < threads.length; j++) {
                threads[j].join();
            }

        } finally {
            httpclient.close();
        }
    }

    /**
     * A thread that performs a GET.
     */
    static class GetThread extends Thread {

        private final CloseableHttpClient httpClient;
        private final HttpContext context;
        private final HttpGet httpget;
        private final int id;

        public GetThread(CloseableHttpClient httpClient, HttpGet httpget, int id) {
            this.httpClient = httpClient;
            this.context = new BasicHttpContext();
            this.httpget = httpget;
            this.id = id;
        }

        /**
         * Executes the GetMethod and prints some status information.
         */
        @Override
        public void run() {
            try {
                System.out.println(id + " - about to get something from " + httpget.getURI());
                CloseableHttpResponse response = httpClient.execute(httpget, context);
                try {
                    System.out.println(id + " - get executed");
                    // get the response body as an array of bytes
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        byte[] bytes = EntityUtils.toByteArray(entity);
                        System.out.println(id + " - " + bytes.length + " bytes read");
                    }
                } finally {
                    response.close();
                }
            } catch (Exception e) {
                System.out.println(id + " - error: " + e);
            }
        }

    }

}