2009-12-15 192 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