我正在使用ThreadPoolExecutor在我的Java应用程序中实现线程。
我有一个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();
}
问题是,在其他线程退出之前打印两个打印输出语句。我想让主线程等待所有其他线程完成。 在正常的Thread实现中,我可以使用join()函数来完成它,但是没有办法在ThreadPool Executor中实现相同的功能。还想问一下,在finally块中编写的代码是否能正确关闭线程池?
谢谢, 阿米特
答案 0 :(得分:4)
CountDownLatch
是为此目的而设计的。可以找到示例here和here。如果事先不知道线程数,请考虑Phaser
,Java 1.7中的新增或UpDownLatch
。
答案 1 :(得分: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());
答案 2 :(得分:1)
首先,您可以使用ThreadPoolExecutor.submit()方法返回Future实例,然后在提交完所有工作项后,您可以通过这些期货进行迭代,并在每个项目上调用Future.get()。
或者,您可以使用ThreadPoolExecutor.invokeAll()准备可运行的工作项并一次性提交,这将等待所有工作项完成,然后您可以获得执行结果或异常调用相同的Future.get(方法。