我遇到了这个并发问题,我已经摸不着头几天了。
基本上,我希望我的ThreadPoolExecutor在关闭之前等待所有任务(未知任务的数量)完成。
public class AutoShutdownThreadPoolExecutor extends ThreadPoolExecutor{
private static final Logger logger = Logger.getLogger(AutoShutdownThreadPoolExecutor.class);
private int executing = 0;
private ReentrantLock lock = new ReentrantLock();
private final Condition newTaskCondition = lock.newCondition();
private final int WAIT_FOR_NEW_TASK = 120000;
public AutoShutdownThreadPoolExecutor(int coorPoolSize, int maxPoolSize, long keepAliveTime,
TimeUnit seconds, BlockingQueue<Runnable> queue) {
super(coorPoolSize, maxPoolSize, keepAliveTime, seconds, queue);
}
@Override
public void execute(Runnable command) {
lock.lock();
executing++;
lock.unlock();
super.execute(command);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
try{
lock.lock();
int count = executing--;
if(count == 0) {
newTaskCondition.await(WAIT_FOR_NEW_TASK, TimeUnit.MILLISECONDS);
if(count == 0){
this.shutdown();
logger.info("Shutting down Executor...");
}
}
}
catch (InterruptedException e) {
logger.error("Sleeping task interrupted", e);
}
finally{
lock.unlock();
}
}
}
意图是任务检查任务计数器(正在执行),如果它等于0,它会阻塞一段时间,然后释放其锁定,以便其他任务可能有机会执行而不是关闭执行者太快了。
但是,它没有发生。执行程序中的所有4个线程都进入等待状态:
"pool-1-thread-4" prio=6 tid=0x034a1000 nid=0x2d0 waiting on condition [0x039cf000]
"pool-1-thread-3" prio=6 tid=0x034d0400 nid=0x1328 waiting on condition [0x0397f000]
"pool-1-thread-2" prio=6 tid=0x03493400 nid=0x15ec waiting on condition [0x0392f000]
"pool-1-thread-1" prio=6 tid=0x034c3800 nid=0x1fe4 waiting on condition [0x038df000]
如果我在Runnable类中放入一个日志语句(应该减慢线程速度),问题似乎就消失了。
public void run() {
// logger.info("Starting task" + taskName);
try {
//doTask();
}
catch (Exception e){
logger.error("task " + taskName + " failed", e);
}
}
问题类似于这篇文章 Java ExecutorService: awaitTermination of all recursively created tasks
我采用了原始的海报解决方案并尝试在afterExecute()中解决竞争条件,但它不起作用。
请帮助阐明这一点。 谢谢。
答案 0 :(得分:1)
你的任务正在等待newTaskCondition
,但没有任何迹象表明这种情况。所以你的线程都堆积起来,等待newTaskCondition
,直到它超时。此外,afterExecute
中的阻止将延迟任务的完成,因此可能不是您想要做的。
如果你想让它等待一段时间,看看是否有更多的工作,这个功能已经存在。只需调用setKeepAliveTime
来设置等待的时间,并设置allowCoreThreadTimeOut
以确保可以终止所有线程(包括核心线程)。
答案 1 :(得分:0)
我找到了解决问题的简单方法。
虽然预先知道任务的数量,并且目的是让主线程等待threadPool中的所有任务完成,但是已知所有任务的提交时间(在查找并提交之后)任务方法已扫描完所有文件。)
我可以简单地调用ThreadPoolExecutor.shutdown()和awaitTermination(Long.MAX_VALUE),这样主线程将无限期地等待ThreadPool完成其任务。