2009-12-15 105 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執行程序中實現同樣的功能。還想問一下,如果finally代碼寫入的代碼關閉了threadpool本身?

感謝, 阿米特

回答

3

要回答你的第二個問題,我認爲你正在做一個合理的工作,試圖清理你的線程池。

關於您的第一個問題,我認爲您要使用的方法是submit而不是execute。我沒有試圖用文本解釋它,而是編寫了一個單元測試的編輯片段,它編寫了許多任務,每個任務都完成了整個工作的一部分,然後回到起點添加結果:

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。但是我沒有意識到Java中有這樣的屬性,所以非常感謝。 – Amit 2009-12-18 10:28:27

+0

非常好。如上所述,「Future」更加靈活,但我也添加了UpDownLatch示例的鏈接。 – trashgod 2009-12-18 22:06:05

+0

另請參閱此相關的[示例](http://stackoverflow.com/a/11372932/230513)。 – trashgod 2012-09-27 03:47:13

1

首先您可以使用ThreadPoolExecutor.submit()方法,該方法返回Future實例,然後在提交所有工作項後,您可以遍歷這些期貨並在每個期貨上調用Future.get()

或者,您可以準備好可運行的工作項目並使用ThreadPoolExecutor.invokeAll()一次全部提交它們,它將等待所有工作項目完成,然後您可以獲取執行結果或調用相同Future.get()方法的異常。

+0

'ThreadPoolExecutor.invokeAll()'在'Callable '對象上運行。是否有一種便捷方法可以爲不會產生任何結果的'Runnable'對象獲得相同的結果? – 2012-09-27 03:41:42