如何在不关闭Executor的情况下等待ThreadPoolExecutor中的所有任务完成?

时间:2010-10-14 01:15:14

标签: java android multithreading wait threadpoolexecutor

我无法使用shutdown()awaitTermination(),因为在等待时可能会将新任务添加到ThreadPoolExecutor中。

所以我正在寻找一种方法,等待ThreadPoolExecutor清空它的队列并完成所有任务,而不会在此之前停止添加新任务。

如果它有任何区别,这适用于Android。

由于

更新:几周后重新访问后,我发现在这种情况下修改后的CountDownLatch对我来说效果更好。我会保留答案标记,因为它更适用于我的要求。

7 个答案:

答案 0 :(得分:67)

如果您有兴趣知道某个任务何时完成,或某一批任务,您可以使用ExecutorService.submit(Runnable)。调用此方法将返回一个Future对象,该对象可放置在Collection中,然后主线程将针对每个对象调用Future.get()进行迭代。这将导致主线程暂停执行,直到ExecutorService处理完所有Runnable任务为止。

Collection<Future<?>> futures = new LinkedList<Future<?>>();
futures.add(executorService.submit(myRunnable));
for (Future<?> future:futures) {
    future.get();
}

答案 1 :(得分:7)

我的方案是一个网络抓取工具,用于从网站获取某些信息然后进行处理。 ThreadPoolExecutor用于加速进程,因为可以在时间加载许多页面。因此,将在现有任务中创建新任务,因为爬网程序将跟随每个页面中的超链接。问题是一样的:主线程不知道所有任务何时完成,并且可以开始处理结果。我用一种简单的方法来确定这一点。它不是很优雅,但在我的情况下工作:

while (executor.getTaskCount()!=executor.getCompletedTaskCount()){
    System.err.println("count="+executor.getTaskCount()+","+executor.getCompletedTaskCount());
    Thread.sleep(5000);
}
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS);

答案 2 :(得分:5)

也许您正在寻找CompletionService来管理批量任务,另请参阅this answer

答案 3 :(得分:3)

(这是尝试通过我自己的调整重现Thilo之前删除的答案。)

我认为您可能需要澄清您的问题,因为存在隐含的无限条件......在某些时候您必须决定关闭执行程序,并且此时它将不再接受任何更多任务。您的问题似乎暗示您要等到知道将不再提交任何其他任务,您只能在自己的应用程序代码中知道。

以下答案将允许您顺利过渡到新的TPE(无论出于何种原因),完成所有当前提交的任务,而不是拒绝新任务到新TPE。它可能会回答你的问题。 @ Thilo也可能。

假设您已经在某处定义了可见的TPE:

AtomicReference<ThreadPoolExecutor> publiclyAvailableTPE = ...;

然后您可以编写TPE交换例程。它也可以使用同步方法编写,但我认为这更简单:

void rotateTPE()
{
   ThreadPoolExecutor newTPE = createNewTPE();
   // atomic swap with publicly-visible TPE
   ThreadPoolExecutor oldTPE = publiclyAvailableTPE.getAndSet(newTPE);
   oldTPE.shutdown();

   // and if you want this method to block awaiting completion of old tasks in  
   // the previously visible TPE
   oldTPE.awaitTermination();
} 

或者,如果你真的不想开玩笑想要杀死线程池,那么你的提交者方需要在某个时候处理被拒绝的任务,你可以使用null来获得新的TPE:

void killTPE()
{
   ThreadPoolExecutor oldTPE = publiclyAvailableTPE.getAndSet(null);
   oldTPE.shutdown();

   // and if you want this method to block awaiting completion of old tasks in  
   // the previously visible TPE
   oldTPE.awaitTermination();
} 

这可能会导致上游问题,调用者需要知道如何处理null

你也可以换掉一个简单拒绝每次新执行的虚拟TPE,但这相当于你在TPE上调用shutdown()时会发生什么。

答案 4 :(得分:1)

如果您不想使用shutdown,请按照以下方法操作:

  1. Future上对提交的所有ExecutorService个任务进行迭代,并根据get()建议在Future对象上阻止来电Tim Bender查看状态

  2. 使用

    之一
    1. ExecutorService
    2. 上使用invokeAll
    3. 使用CountDownLatch
    4. 使用ExecutorsinvokeAll() CountDownLatch(自java 8开始)
  3. 执行者服务上的

    public boolean primeNumberCheck(int n) { // exclude numbers with divisor 2 or 3 if (n % 2 == 0) { return false; } if (n % 3 == 0) { return false; } // all integers can be expressed as (6k + i) for some integer k and // for i = −1, 0, 1, 2, 3, or 4; // 2 divides (6k + 0), (6k + 2), (6k + 4); and 3 divides (6k + 3). // so we only have to test numbers of the form 6k +- 1 int k = 1; int i = -1; // we only need to check candidates up to SQRT(n) double sqrtN = Math.Sqrt(n); int candidateDivisor = getCandidateDivisor(k, i); while (candidateDivisor < sqrtN) { if (n % candidateDivisor == 0) { return false; } // flip i between -1 and 1 i = -i; // when i flips back to -1, increment k if (i < 0) { k++; } candidateDivisor = getCandidateDivisor(k, i); } return true; } private int getCandidateDivisor(k, i) { return (6 * k) + i; } 也实现了<TextView android:id="@+id/tv_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="@dimen/margin_5" android:textColor="@color/white" />

    的相同目的

    相关的SE问题:

    ForkJoinPool

答案 5 :(得分:0)

你可以在 Runner 类上调用 waitTillDone()

<div class="form-group">
   <div class="input-group">
      <span class="input-group-addon" id="input-group-addon-captcha"><img id="cap-img" src="captcha.php"></span>
      <input id="seo-captcha" name="" class="form-control" placeholder="Please Enter Text" type="text">
      <span class="input-group-addon seo-addon-right"><button class="btn btn-xs btn-q" id="reload"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
      </button></span>
   </div>
</div>

  <script>
  $(function() {            
    $('#reload').click(function(){  
     $('#cap-img').attr('src', 'captcha.php?' + (new Date).getTime());
    });
    });
 </script>

要使用它,请将此gradle / maven依赖项添加到项目中:Runner runner = Runner.runner(10); runner.runIn(2, SECONDS, runnable); runner.run(runnable); // each of this runnables could submit more tasks runner.waitTillDone(); // blocks until all tasks are finished (or failed) // and now reuse it runner.runIn(500, MILLISECONDS, callable); runner.waitTillDone(); runner.shutdown();

有关详情,请点击此处:https://github.com/MatejTymes/JavaFixes或此处:http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html

答案 6 :(得分:0)

尝试使用队列大小,活动任务计数如下所示

 while (executor.getThreadPoolExecutor().getActiveCount() != 0 || !executor.getThreadPoolExecutor().getQueue().isEmpty()){
                     try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
        }
相关问题