Java 等待所有任务(未知编号)完成-ThreadPoolExecutor

Java 等待所有任务(未知编号)完成-ThreadPoolExecutor,java,concurrency,Java,Concurrency,我遇到了这个并发问题,这让我挠头好几天了 基本上,我希望我的ThreadPoolExecutor在关闭之前等待所有任务(未知任务数)完成 public class AutoShutdownThreadPoolExecutor extends ThreadPoolExecutor{ private static final Logger logger = Logger.getLogger(AutoShutdownThreadPoolExecutor.class); private

我遇到了这个并发问题,这让我挠头好几天了

基本上,我希望我的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();
        }
    }
}
如果我在Runnable类中放入一条log语句(应该会减慢线程的速度),那么问题似乎就消失了

public void run() {
    //  logger.info("Starting task" + taskName);
        try {
            //doTask();
        }
        catch (Exception e){
            logger.error("task " + taskName + " failed", e);
        }
}
这个问题类似于这篇文章

我采用了最初的poster解决方案,并尝试在afterExecute()中解决竞争条件,但它不起作用

请帮我解释一下。
谢谢。

您的任务正在等待此
newTaskCondition
,但没有任何东西显示此情况。因此,所有线程都会堆积起来,等待
newTaskCondition
,直到超时。此外,在执行后阻塞
会延迟任务的完成,因此这可能不是您想要做的


如果您想让它等待一段时间,看看是否有更多的工作,这个功能已经存在。只需调用设置等待时间,并设置为确保所有线程(包括核心线程)都可以终止。

我找到了一个非常简单的解决方案

虽然任务的数量事先未知,目的是让主线程等待线程池中的所有任务完成,但所有任务提交的时间是已知的(在find and submit-task方法扫描了所有文件之后)


我可以简单地调用ThreadPoolExecutor.shutdown()并等待终止(Long.MAX_VALUE),以便主线程将无限期地等待ThreadPool完成其任务。

使用CountDownLatch如何?任务数事先未知。该程序扫描一个目录,查找其子文件夹中的所有文件,并对每个文件执行一些数字处理任务。这就是它的意图。检查是否没有更多的任务->等待并释放锁一段时间,(如果有新任务,他们应该已经获取了此锁)->唤醒并重新获取锁->再次检查任务数是否仍然为0->如果是,则关闭执行器,如果不只是退出任务。我想,在这种情况下,没有必要发出让线程醒来的信号?@TommyQ,这就是正在发生的事情——一个任务运行,它看到没有更多线程,它开始等待120秒。重复四次,现在您有四个等待任务。在计时器过期之前,没有任何东西会唤醒它们,如果因为线程忙着等待120秒而耗尽了线程,那么,太糟糕了。内置keepalive计时器有什么问题?setKeepAliveTime仅适用于多余的线程?我设置corePoolsize=maxPoolsize;
public void run() {
    //  logger.info("Starting task" + taskName);
        try {
            //doTask();
        }
        catch (Exception e){
            logger.error("task " + taskName + " failed", e);
        }
}