Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread is blocked when to reuse apache httpclient

I used apache httpclient 4.3.4, I want to reuse httpclient instance in work thread, but the thread was blocked when httpclient post data at second time.

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();
      }
    }
  }

It seem that the connections was ran out, but I actually closed all resource.

like image 974
tank1920 Avatar asked Jul 23 '14 07:07

tank1920


1 Answers

You can not use a Simple Connection Manager in a multi threaded environment, even though this class is thread-safe it ought to be used by one execution thread only.

Extracted from the Apache HTTP Components tutorial

2.3.2. Simple connection manager

BasicHttpClientConnectionManager is a simple connection manager that maintains only one connection at a time. Even though this class is thread-safe it ought to be used by one execution thread only. BasicHttpClientConnectionManager will make an effort to reuse the connection for subsequent requests with the same route. It will, however, close the existing connection and re-open it for the given route, if the route of the persistent connection does not match that of the connection request. If the connection has been already been allocated, then java.lang.IllegalStateException is thrown.

so, you have use a Pooling connection manager

2.3.3. Pooling connection manager

PoolingHttpClientConnectionManager is a more complex implementation that manages a pool of client connections and is able to service connection requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route for which the manager already has a persistent connection available in the pool will be serviced by leasing a connection from the pool rather than creating a brand new connection.

PoolingHttpClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total. For many real-world applications these limits may prove too constraining, especially if they use HTTP as a transport protocol for their services.

You can take a look at the Threaded request execution example

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);
            }
        }

    }

}
like image 110
vzamanillo Avatar answered Oct 12 '22 07:10

vzamanillo