2009-12-15 8 views
2

ThreadPoolExecutor를 사용하여 Java 응용 프로그램에서 스레드를 구현하고 있습니다.주 스레드가 ThreadPoolExecutor에서 다른 스레드가 완료 될 때까지 대기하는 방법

필자는 완성을 실행하기 위해 각 노드를 구문 분석하고 스레드에 추가해야하는 XML을 가지고 있습니다. 내 구현은 다음과 같습니다 :

parse_tp는 스레드 풀 개체입니다. & ParseQuotesXML은 run 메소드가있는 클래스입니다.

 try {  
      List children = root.getChildren();    
     Iterator iter = children.iterator(); 

     //Parsing the XML  
     while(iter.hasNext()) {  
      Element child = (Element) iter.next();   
      ParseQuotesXML quote = new ParseQuotesXML(child, this);   
      parse_tp.execute(quote);   
     } 
    System.out.println("Print it after all the threads have completed"); 
     catch(Exception ex) { 
     ex.printStackTrace();  
     } 
     finally { 
    System.out.println("Print it in the end."); 
if(!parse_tp.isShutdown()) { 
       if(parse_tp.getActiveCount() == 0 && parse_tp.getQueue().size() == 0) { 
        parse_tp.shutdown();      
       } else { 
        try { 
         parse_tp.awaitTermination(30, TimeUnit.SECONDS); 
        } catch (InterruptedException ex) { 
         log.info("Exception while terminating the threadpool "+ex.getMessage()); 
         ex.printStackTrace(); 
        } 
       } 
      } 
      parse_tp.shutdown(); 
     } 

문제는 두 개의 인쇄 출력 문이 다른 스레드가 종료되기 전에 인쇄된다는 것입니다. 주 스레드가 다른 모든 스레드가 완료 될 때까지 대기하도록하고 싶습니다. 정상적인 스레드 구현에서는 join() 함수를 사용하여이를 수행 할 수 있지만 ThreadPool Executor에서 동일한 기능을 수행하는 방법은 없습니다. 또한 코드가 마침내 스레드 풀을 닫으려면 블록 작성된 경우 물어보고 싶습니다?

덕분에, 미트

답변

3

두 번째 질문에 대답하려면 스레드 풀을 정리하려고 합리적인 작업을 수행하고 있다고 생각합니다.

첫 번째 질문과 관련하여 사용하려는 방법이 execute이 아닌 submit이라고 생각합니다. 텍스트로 설명하려고하기보다는, 내가 작성한 단위 테스트의 편집 된 단편을 통해 많은 작업을 수행하고 각자가 전체 작업의 일부를 수행 한 다음 시작 지점에서 다시 결과를 추가합니다.

final AtomicInteger messagesReceived = new AtomicInteger(0); 

// ThreadedListenerAdapter is the class that I'm testing 
// It's not germane to the question other than as a target for a thread pool. 
final ThreadedListenerAdapter<Integer> adapter = 
    new ThreadedListenerAdapter<Integer>(listener); 
int taskCount = 10; 

List<FutureTask<Integer>> taskList = new ArrayList<FutureTask<Integer>>(); 

for (int whichTask = 0; whichTask < taskCount; whichTask++) { 
    FutureTask<Integer> futureTask = 
     new FutureTask<Integer>(new Callable<Integer>() { 
     @Override 
     public Integer call() throws Exception { 
      // Does useful work that affects messagesSent 
      return messagesSent; 
     } 
    }); 
    taskList.add(futureTask); 
} 

for (FutureTask<Integer> task : taskList) { 
    LocalExecutorService.getExecutorService().submit(task); 
} 

for (FutureTask<Integer> task : taskList) { 
    int result = 0; 
    try { 
     result = task.get(); 
    } catch (InterruptedException ex) { 
     Thread.currentThread().interrupt(); 
    } catch (ExecutionException ex) { 
     throw new RuntimeException("ExecutionException in task " + task, ex); 
    } 
    assertEquals(maxMessages, result); 
} 

int messagesSent = taskCount * maxMessages; 
assertEquals(messagesSent, messagesReceived.intValue()); 

이 부분은 사용자가하려는 것과 유사하다고 생각합니다. 주요 구성 요소는 submitget 메소드입니다.

4

CountDownLatch이 매우 목적을 위해 설계되었습니다. 예는 herehere입니다. 스레드의 수가 미리 알려지지 않은 경우 Phaser (Java 1.7의 새로운 기능) 또는 UpDownLatch을 고려하십시오.

+0

고맙습니다. trashgod,하지만 파싱해야하는 xml 노드의 정확한 개수가 없으므로 CountDownLatch를 사용할 수 없게됩니다. 하지만 자바에서 사용할 수있는 이러한 속성을 알지 못했기 때문에이 점에 대해 많은 감사를드립니다. – Amit

+0

우수. 위에서 제안한 것처럼'Future'는 좀 더 유연하지만 UpDownLatch 예제에 대한 링크도 추가했습니다. – trashgod

+0

관련 [예제] (http://stackoverflow.com/a/11372932/230513)도 참조하십시오. – trashgod

1

먼저 ThreadPoolExecutor.submit() 메서드를 사용하면 Future 인스턴스를 반환 할 수 있습니다. 그런 다음 모든 작업 항목을 제출 한 후에 그 미래를 반복하고 각각에 Future.get()을 호출 할 수 있습니다.

또는 실행 가능 작업 항목을 준비하고 ThreadPoolExecutor.invokeAll()을 사용하여 한꺼번에 제출할 수 있습니다.이 작업 항목은 모든 작업 항목이 완료 될 때까지 대기하고 실행 결과 또는 예외가 동일한 Future.get() 메소드를 호출 할 때까지 대기합니다.

+0

'ThreadPoolExecutor.invokeAll()'은'Callable '객체에서 작동합니다. 결과를 생성하지 않는'Runnable' 객체에 대해서 같은 결과를 얻을 수있는 편리한 메소드가 있습니까? –

관련 문제