如何等待所有线程完成

时间:2012-11-20 12:18:29

标签: java multithreading

我创建了一些工作流程,如何等待我创建的所有线程。此示例适用于99%的情况,但有时候方法waitForAllDone会在所有线程完成之前完成。我知道因为在waitForAllDone之后我正在关闭正在使用创建线程的流,因此发生异常

Caused by: java.io.IOException: Stream closed

我的主题开始于:

  @Override
  public void run() {
    try {
      process();
    } finally {
      Factory.close(this);
    }
  }

结束:

  protected static void close(final Client client) {
    clientCount--;
  }

当我创建线程时,我称之为:

  public RobWSClient getClient() {
    clientCount++;
    return new Client();
  }
工厂内的

和clientCount变量:

  private static volatile int clientCount = 0;

等待:

  public void waitForAllDone() {
    try {
      while (clientCount > 0) {
        Thread.sleep(10);
      }

    } catch (InterruptedException e) {
      LOG.error("Error", e);
    }
  }

3 个答案:

答案 0 :(得分:5)

您需要通过clientCount保护synchronized的修改和阅读。主要问题是clientCount--clientCount++不是原子操作,因此两个线程可以执行clientCount-- / clientCount++并最终得到错误的结果。

如上所述简单地使用volatile只能在场上的所有操作都是原子的情况下才能工作。由于它们不是,您需要使用一些锁定机制。正如安东所说,AtomicInteger在这里是一个很好的选择。请注意,它应该是finalvolatile,以确保它不是线程本地的。

话虽如此,Java 1.5后的一般规则是使用ExecutorService而不是Threads。与Guava的Futures类结合使用可以让所有人完成如下这样简单:

Future<List<?>> future = Futures.successfulAsList(myFutureList);
future.get();
// all processes are complete

Futures.successfulAsList

答案 1 :(得分:3)

我不确定你的代码的其余部分是否有问题,但你不能像这样增加volatile变量 - clientCount++;请改用AtomicInteger

答案 2 :(得分:1)

等待线程终止的最佳方法是使用其中一个高级并发工具。 在这种情况下,最简单的方法是使用ExecutorService。

您将以这种方式向执行者“提供”新任务:

...
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
...

Client client = getClient(); //assuming Client implements runnable
executor.submit(client);
...

public void waitForAllDone() {
    executor.awaitTermination(30, TimeUnit.SECOND) ; wait termination of all threads for 30 secs
... 
}

通过这种方式,您不会在繁忙的等待或睡眠/唤醒周期中浪费宝贵的CPU周期。 有关详细信息,请参阅ExecutorService文档。