我需要做一些多线程工作,我使用 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);
?
最佳答案
I call my ContentParser.queueExecutor from another class, so after all jobs are submitted I do:
这听起来像是有人在调用 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
字段。您无法控制外部类如何(或在这种情况下何时)调用池中的关键方法。我会将其设为私有(private),然后在您的 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(...)
.
关于java cachedThreadPool 杀死提交的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31746310/