2014-07-23 7 views
2

아파치 httpclient 4.3.4를 사용했는데, 작업 스레드에서 httpclient 인스턴스를 재사용하고 싶지만, 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(); 
     } 
    } 
    } 

연결이 끊긴 것 같지만 사실 모든 리소스를 닫았습니다.

답변

3

단순 연결 관리자을 다중 스레드 환경에서 사용할 수 없습니다.이 클래스는 스레드 안전성을 갖지만 하나의 실행 스레드에서만 사용해야합니다.

Apache HTTP Components tutorial

2.3.2에서 추출 하였다. 단순 연결 관리자

BasicHttpClientConnectionManager는 이 한 번에 하나의 연결 만 유지하는 간단한 연결 관리자입니다. 이 클래스는 스레드 안전하지만 하나의 실행 스레드에서만 사용해야합니다. BasicHttpClientConnectionManager는 같은 경로를 사용하는 후속 요청에 연결을 다시 사용하기 위해 노력합니다. 그러나 의 경우 기존 연결을 닫은 다음 영구 연결 경로가 연결 요청의 과 일치하지 않으면 지정된 경로로 다시 연결합니다. 연결이 이미 으로 할당 된 경우 java.lang.IllegalStateException이 발생합니다.

그래서, 당신은 풀링 연결 관리자

2.3.3을 사용합니다. 연결 관리자에게

PoolingHttpClientConnectionManager을 풀링하는 것은 더 복잡한 구현 클라이언트 연결의 풀을 관리하고 여러 실행 스레드에서 연결 요청을 처리 할 수 ​​ 이다. 연결은 경로별로 풀링 된 입니다. 관리자가 이미 풀에서 영구 연결을 사용할 수있는 경로를 요청하면 새 연결을 만들지 않고 풀에서 연결을 임대하여 을 처리 할 수 ​​있습니다.

PoolingHttpClientConnectionManager는 최대 개의 연결 수를 라우팅 단위로 유지합니다. 기본적으로이 구현에서는 지정된 경로 당 2 개 이하의 동시 연결을 생성하며 총 20 개의 연결은 더 이상 생성하지 않습니다. 많은 실제 세계에서 응용 프로그램의 경우 이러한 제한은 너무 제한적일 수 있습니다. 특히 HTTP를 서비스 용 전송 프로토콜로 사용하는 경우 특히 그렇습니다.

당신은 아직도 풀에서 연결을 사용할 때 스레드를 차단 PoolingHttpClientConnectionManager을 시도 한 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); 
      } 
     } 

    } 

} 
+1

좀 걸릴 수 있습니다, 그래서 BasicHttpClientConnectionManager를 사용하려고합니다. 스레드가 데이터를 게시하는 데 계속해서 사용할 수 있도록 연결을 해제하는 방법을 얻길 바랍니다. – tank1920

+0

차단의 원인을 발견했습니다. 서버의 NOCONTENT 응답이 본문을 가져 왔기 때문에 연결을 해제 할 수 없습니다. NOCONTENT 응답을 테스트 할 환경이 있기 때문에 테스트하는 것은 큰 실수입니다. – tank1920

관련 문제