2010-01-21 3 views
1

여러 스레드와 병렬로 HTTP 요청을 보낼 수있는 코드를 작성했습니다. 부모 스레드는 thread.join()을 사용하여 모든 자식 스레드가 완료 될 때까지 대기합니다. 하지만 내 코드에서 join()은 때때로 작동하지 않았습니다. 누군가 내 코드의 문제점을 지적 할 수 있습니까? 감사.Android에서 스레드 조인이 작동하지 않습니까?

D/:multiProcessRequest( 964): Thread 18 is still alive : RUNNABLE 

D/:multiProcessRequest( 964): Thread 20 is still alive : RUNNABLE 
을 :

D/GetThread:run( 964): 16 - get executed 
D/GetThread:run( 964): 16 - 9444 bytes read from ...... 
D/dalvikvm( 964): GC freed 675 objects/463256 bytes in 84ms 
D/GetThread:run( 964): 16: [[email protected] 
D/GetThread:run( 964): 17 - get executed 
D/GetThread:run( 964): 17 - 9000 bytes read from ...... 
D/GetThread:run( 964): 17: [[email protected] 
D/GetThread:run( 964): 18 - get executed 
D/:multiProcessRequest( 964): Thread 18 is still alive : RUNNABLE 

D/:multiProcessRequest( 964): Thread 20 is still alive : RUNNABLE 
D/dalvikvm( 964): threadid=17 wakeup: interrupted 

D/:multiProcessRequest( 964): ConnectionManager shutted down. 

D/GetThread:run( 964): 18 - 9427 bytes read from ...... 
D/$GetThread:run( 964): 18: [[email protected] 
D/dalvikvm( 964): GC freed 1269 objects/666456 bytes in 90ms 
W/ExpatReader( 964): DTD handlers aren't supported. 
D/$GetThread:run( 964): 20 - get executed 
D/$GetThread:run( 964): 20 - 12751 bytes read ...... 
D/$GetThread:run( 964): 20: [[email protected] 

이 두 라인 아래 두 개의 스레드가 여전히) (가입 후 실행중인 것을 보여 주었다 :() 로그에서

/** 
* @param urlSet 
*   , a set of link URLs (Can not be null) 
* @return Map<link URL, response in byte array> 
* @throws InterruptedException 
*/ 
protected Map<String, byte[]> multiProcessRequest(Set<String> urlSet) 
     throws InterruptedException { 

    if (urlSet.isEmpty()) { 
     return null; 
    } 

    // Create and initialize HTTP parameters 
    HttpParams params = new BasicHttpParams(); 
    ConnManagerParams.setMaxTotalConnections(params, MAX_CONNECTIONS); 
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 

    // Create and initialize scheme registry 
    SchemeRegistry schemeRegistry = new SchemeRegistry(); 
    schemeRegistry.register(new Scheme("http", PlainSocketFactory 
      .getSocketFactory(), 80)); 

    // Create an HttpClient with the ThreadSafeClientConnManager. 
    // This connection manager must be used if more than one thread will 
    // be using the HttpClient. 
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, 
      schemeRegistry); 
    m_httpClient = new DefaultHttpClient(cm, params); 

    List<String> urlList = new ArrayList<String>(urlSet); 

    // create a thread for each URI 
    GetThread[] threads = new GetThread[urlSet.size()]; 

    for (int i = 0; i < threads.length; i++) { 
     HttpGet httpget = new HttpGet(urlList.get(i)); 
     threads[i] = new GetThread(m_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(); 
    } 

    // FIXME: debug for statement only 
    for (int j = 0; j < threads.length; j++) { 
     if (threads[j].isAlive()) { 
      s_logger.debug("Thread " + (j+1) + " is still alive : " + threads[j].getState()); 
     } 
    } 

    // When HttpClient instance is no longer needed, 
    // shut down the connection manager to ensure 
    // immediate deallocation of all system resources 
    m_httpClient.getConnectionManager().shutdown(); 

    s_logger.debug("ConnectionManager shutted down."); 

    /* Prepare the return. */ 
    Map<String, byte[]> urlToResponseMap = new HashMap<String, byte[]>(
      threads.length); 

    for (int i = 0; i < threads.length; ++i) { 
     urlToResponseMap.put(urlList.get(i), threads[i].getResult()); 
    } 

    return urlToResponseMap; 
} 

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

    private final HttpClient httpClient; 
    private final HttpContext context; 
    private final HttpGet httpget; 
    private final int internalId; 

    /** The response result of the URL get. */ 
    private byte[] result; 

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

    public byte[] getResult() { 
     return result; 
    } 

    /** 
    * Executes the GetMethod and prints some status information. 
    */ 
    @Override 
    public void run() { 

     s_logger.debug(internalId + " - about to get something from " 
       + httpget.getURI()); 

     try { 

      // execute the method 
      HttpResponse response = httpClient.execute(httpget, context); 

      s_logger.debug(internalId + " - get executed"); 

      // get the response body as an array of bytes 
      HttpEntity entity = response.getEntity(); 
      if (entity != null) { 
       result = EntityUtils.toByteArray(entity); 

       s_logger.debug(internalId + " - " + result.length 
         + " bytes read from " + httpget.getURI()); 
       s_logger.debug(internalId + ": " + result); 
      } 

     } catch (Exception e) { 
      httpget.abort(); 
      s_logger.error(internalId + " - error: ", e); 
     } 
    } 

} 

, 나는 multiProcessRequest를 실행 한 후 이러한 디버그 메시지를 보았다

답변

1

흠 ... 코드가 제게 좋았습니다. 조인 후에도 어떤 스레드가 살아 있는지 알 수 없습니다. 조인이 예외를 throw하지 않는 한, 로깅 문은 실행되지 않습니다.

다른 JVM 또는 플랫폼에서 사용해 보셨습니까?

+0

로그를 볼 수 있으므로 안드로이드 시뮬레이터에서만 시도했습니다. JVM에서이 코드를 사용해 보자. – user256239

+0

JVM에서 동일한 코드를 시도했지만 문제가 재현되지 않았습니다. 이상해. 적어도 Android 시뮬레이터에는 스레드 동기화 문제가있는 것 같습니다. 어쨌든, 감사합니다. – user256239

+0

문제 없습니다. Android 에뮬레이터에 대한 버그를 신고해야합니다. –

관련 문제