2012-11-20 4 views
0

내가 만든 모든 스레드를 기다리는 방법을 몇 가지 워크 플로로 만들었습니다. 이 예제는 99 %의 경우에서 작동하지만 waitForAllDone 메서드가 더 빨리 완료되고 모든 스레드가 완료되는 경우가 있습니다. waitForAllDone 후 내가 만든 스레드를 사용하는 스트림을 폐쇄하고 있기 때문에 그래서 다음 예외가 발생 알고모든 스레드가 완료 될 때까지 기다리는 방법

Caused by: java.io.IOException: Stream closed 

내 스레드 시작 :

@Override 
    public void run() { 
    try { 
     process(); 
    } finally { 
     Factory.close(this); 
    } 
    } 

마감 : 나는

protected static void close(final Client client) { 
    clientCount--; 
    } 

을 만드는 thread 전화 :

public RobWSClient getClient() { 
    clientCount++; 
    return new Client(); 
    } 
공장 내부

및 clientCount 변수 :

private static volatile int clientCount = 0; 

대기 :

public void waitForAllDone() { 
    try { 
     while (clientCount > 0) { 
     Thread.sleep(10); 
     } 

    } catch (InterruptedException e) { 
     LOG.error("Error", e); 
    } 
    } 
+0

자바의 세마포어 문서를 확인하십시오. 이 예제는 거의 동일하며 필요한 것은 다음과 같습니다. http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html –

답변

5

당신은 synchronized를 통해 clientCount의 수정 및 읽기를 보호해야합니다. 가장 큰 문제는 clientCount--clientCount++이 원자 적 연산이 아니므로 두 스레드가 clientCount--/clientCount++을 실행하여 잘못된 결과로 끝날 수 있다는 것입니다.

위에서 설명한대로를 단순히 사용하면 필드의 모든 작업이 원자적일 경우에만 작동합니다. 그렇지 않기 때문에 잠금 메커니즘을 사용해야합니다. 안톤 주 (州)는 AtomicInteger을 훌륭한 선택으로 여기고 있습니다. 스레드 로컬이 아닌지 확인하려면 final 또는 volatile이어야합니다.

즉, Java 1.5 이후 일반 규칙은 Threads 대신 ExecutorService을 사용합니다. 모든 기다리고 만들 수있는 구아바의 Futures 클래스와 연동 해이 사용하는만큼 단순하게 완료 :

Future<List<?>> future = Futures.successfulAsList(myFutureList); 
future.get(); 
// all processes are complete 

Futures.successfulAsList

+0

하지만 다른 스레드를 생성하는 스레드는 하나뿐입니다. . 그렇다면 누가이 가치를 부각시킬 수 있습니까? – hudi

+0

적절한 보호를 설정하는 한 원하는 모든 스레드 수에서 값을 증가시킬 수 있습니다. –

+0

확인하고 테스트 할 수있는 옵션이 있습니까? – hudi

3

내가 당신의 코드의 나머지 부분은 아무런 문제가 없다는 것을 잘 모르겠지만, 당신은 이처럼 휘발성 변수를 증가시킬 수 없습니다 - clientCount++; 대신 AtomicInteger을 사용하십시오.

+0

왜 나는 그것을 늘릴 수 없습니다. 문서를 게시 할 수 있습니까? – hudi

+0

원자 적 조작이 아니기 때문에 원인이됩니다. A = A + 1 동안 A의 값은 다른 스레드에 의해 변경 될 수 있습니다. – Anton

+4

@hudi는 아마존에서 http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601을 주문하는 것을 고려합니다. 시행 착오 접근 방식으로 스레드 안전 코드를 작성하십시오 –

1

스레드가 종료 될 때까지 기다리는 가장 좋은 방법은 높은 수준의 동시성 기능 중 하나를 사용하는 것입니다. 이 경우 가장 쉬운 방법은 ExecutorService를 사용하는 것입니다.

당신은 '제안'이 방법으로 집행에 새 작업 것이다 : 당신은 바쁜 대기 또는 수면/각성주기에서 중요한 CPU 사이클을 낭비하지 말라 이런 식으로

... 
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE); 
... 

Client client = getClient(); //assuming Client implements runnable 
executor.submit(client); 
... 

public void waitForAllDone() { 
    executor.awaitTermination(30, TimeUnit.SECOND) ; wait termination of all threads for 30 secs 
... 
} 

. 자세한 내용은 ExecutorService 문서를 참조하십시오.

관련 문제