【问题标题】:How can I tell that threads in ThreadPoolExecutor are done?如何判断 ThreadPoolExecutor 中的线程已完成?
【发布时间】:2014-01-06 23:09:53
【问题描述】:

我正在编写代码,我需要确保在提交结果之前没有线程当前在线程池中运行(以避免丢失我应该放入提交中的数据)。为此,我正在使用:

while (_executor.getActiveCount() > 0)
{
  try
  {
    Thread.sleep(10); // milliseconds
  }
  catch (InterruptedException e)
  {
    // OK do nothing
  }
}

但一位同事在评论中指出,getActiveCount 的文档指出:

  • 返回活动线程的大致数量
  • 执行任务。

那么,当池中仍有活动线程时,我是否会退出 while 循环?如果是这样,等待我的所有工作线程完成的正确方法是什么?

编辑:提供更多上下文:这是一个在线系统,其中包含执行程序服务的任务会无限期地运行。工作通过消息系统进入,放在执行程序中的一个线程上,不需要任何同步,然后工作进入消息系统的另一个队列。我不想杀死执行者等待任务完成。

【问题讨论】:

标签: java concurrency threadpool


【解决方案1】:

用例:需要在池线程完成后清理线程局部变量,并且此清理可能需要很长时间(例如连接关闭)。只有在那之后,主线程才能继续。

工作线程可以在某个集合中注册自己。对于该覆盖 start() 和 run() 并将自定义线程工厂传递给 ThreadPoolExecutor:

class MyThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(final Runnable r) {
        return new MyThread(r);
    }
...

class Some {
    void waitAllThreads() {
        Thread worker;
        while ((worker = workerThreads.poll()) != null) {
            worker.join();
        }
    }
    ...

class MyThread extends Thread {

    @Override
    public synchronized void start() {
        if (getState() == State.NEW) {
            some.workerThreads.offer(this);
        }
        super.start();
    }

    @Override
    public void run() {
        try {
            super.run();
        } finally {
            some.workerThreads.remove(this);
        }
    }

    ...

【讨论】:

    【解决方案2】:

    当任务提交给执行器时,它们会返回 Futures,这表明它们何时完成。这是首选的机制。

    您可以使用 JDK ExecutorService shutdown/awaitTermination。

    【讨论】:

    • Executors 返回无效。要获得Futures,您需要使用CompletionService。
    • @bstempi ExecutorServices 返回 Futures 和 void。 ExecutorService.submit 返回 Runnables 和 Callables 的期货。
    • JDK 接口“ExecutorService”——以及所有实现类——绝对返回 Futures。
    • @AndreyChaschev @user2684301 我在看Java的Executor接口:docs.oracle.com/javase/7/docs/api/java/util/concurrent/…
    【解决方案3】:

    _executor.awaitTermination(); 应该可以完成这项工作。现在,它实际上不会等待线程关闭,而是等待所有可用任务终止。

    您还可以将keepAliveTime 提供给线程池构造函数以立即终止空闲线程:

    ExecutorService executor = new ThreadPoolExecutor(0, 10, 0L /* keepAlive */, 
            TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    

    【讨论】:

      【解决方案4】:

      您可能需要考虑使用CompletionService (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CompletionService.html)。

      CompletionService 包装 ExecutorService 并在提交任务时返回 Future。通过维护这些Futures 的列表,您可以查看您正在等待的作业是否已完成。它还有一个额外的优势,即您可以让其他人使用相同的ExecutorService,因为您有一些会计手段,

      【讨论】:

        【解决方案5】:

        要通知线程它应该清理并终止,请使用中断方法。 t.interrupt();

        最好从 catch 块打印或记录您的错误。

        【讨论】:

          猜你喜欢
          • 2014-07-19
          • 1970-01-01
          • 2017-09-18
          • 1970-01-01
          • 2013-01-14
          • 2014-01-13
          • 2021-12-11
          • 2010-12-26
          • 2011-07-25
          相关资源
          最近更新 更多