我需要做一些多线程工作,并使用ExecutorService.newCachedThreadPool()
并提交从队列中检索的一些作业。
public class ContentParser {
public static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// ...
public static void queueExecutor(Content content) {
String url = "";
while ((url = queue.poll()) != null){
LOG.info("Picked url " + url);
cachedThreadPool.submit(new ParserCallable(content, url));
}
}
// ...
private static class ParserCallable implements Runnable {
private Content content;
private String url;
private ParserCallable(Content content, String url) {
this.url = url;
this.content = content;
}
@Override
public void run(){
new FontParser().fontSearcher(content, url);
}
}
因此每个线程都会创建一个FontParser
的新实例,并且在其中我做了一些工作。
我从另一个班级打电话给我ContentParser.queueExecutor
,所以在完成所有工作后我都会这样做:
ContentParser.cachedThreadPool.shutdown();
ContentParser.cachedThreadPool.awaitTermination(5l, TimeUnit.MINUTES);
但即使工作没有完成也不等待,它只会杀死我的线程。
也许是因为我在每个帖子中都创建了一个新实例new FontParser().fontSearcher(content, url);
?
答案 0 :(得分:0)
我从另一个类调用我的ContentParser.queueExecutor,所以在提交所有作业之后我做了:
听起来你在说某人正在呼叫cachedThreadPool.shutdown()
但是工作仍然被提交到池中。这绝不应该发生。只有在shutdown()
循环完成后才应调用poll()
。
我建议您在queueExecutor(...)
方法中执行以下操作:
while ((url = queue.poll()) != null){
LOG.info("Picked url " + url);
cachedThreadPool.submit(new ParserCallable(content, url));
}
// shutdown _after_ all jobs have been submitted
cachedThreadPool.shutdown();
此外,一般情况下,将字段公开是一种不好的做法 - 尤其是在这种情况下,您的cachedThreadPool
字段。您无法控制外部类在池上调用关键方法的方式(或在此情况下)。我将其设为私有,然后在ContentParser
类上使用await方法:
private static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
...
public static void awaitPoolTermination(/* maybe timeout args here */) {
cachedThreadPool.awaitTermination(5l, TimeUnit.MINUTES);
}
这样可以更好地控制您的线程池,并且不允许在不正确的位置关闭。因此,ContentParser
方法的来电者先拨打contentParser.queueExecutor(...)
,然后拨打contentParser.awaitPoolTermination(...)
。