在 Java 中等待多个线程完成

IT小君   2021-10-16T06:38:51

在我的程序执行过程中,启动了许多线程。线程的数量取决于用户定义的设置,但它们都使用不同的变量执行相同的方法。

在某些情况下,在执行过程中需要进行清理,其中一部分是停止所有线程,但我不希望它们立即停止,我只是设置了一个他们检查的变量来终止它们。问题是在线程停止之前最多可能有 1/2 秒。但是,我需要确保在继续清理之前所有线程都已停止。清理是从另一个线程执行的,所以从技术上讲,我需要这个线程等待其他线程完成。

我已经想到了几种方法来做到这一点,但它们似乎都过于复杂。我希望有一些方法可以等待一组线程完成。这样的东西存在吗?

谢谢。

评论(5)
IT小君

只需一一加入:

for (Thread thread : threads) {
  thread.join();
}

(您需要对 做一些事情InterruptedException,并且您可能希望提供超时以防出现问题,但这是基本思想......)

2021-10-16T06:38:51   回复
IT小君

如果您使用的是 java 1.5 或更高版本,您可以尝试CyclicBarrier您可以将清理操作作为其构造函数参数传递,并barrier.await()在需要清理时调用所有线程。

2021-10-16T06:38:52   回复
IT小君

你看过里面的Executorjava.util.concurrent吗?您可以通过ExecutorService. 它为您提供了一个可用于取消线程或等待它们完成的对象。

2021-10-16T06:38:52   回复
IT小君

自己定义一个实用方法(或多个方法):

public static waitFor(Collection<? extends Thread) c) throws InterruptedException {
    for(Thread t : c) t.join();
}

或者你可能有一个数组

public static waitFor(Thread[] ts) throws InterruptedException {
    waitFor(Arrays.asList(ts));
}

另外,您可以看看使用CyclicBarrierjava.util.concurrent库来实现任意交会多个线程之间的点。

2021-10-16T06:38:52   回复
IT小君

如果您控制线程的创建(提交给 ExecutorService),那么您似乎可以使用ExecutorCompletionService 查看ExecutorCompletionService?如果我们有 invokeAll 为什么需要一个?那里的各种答案。

如果您不控制线程创建,这里有一种方法允许您“在线程完成时一个一个地”加入线程(并知道哪个线程先完成等等),其灵感来自 ruby ThreadWait类。基本上,通过更新在其他线程终止时发出警报的“观察线程”,您可以知道许多线程中的“下一个”线程何时终止。

你会像这样使用它:

JoinThreads join = new JoinThreads(threads);
for(int i = 0; i < threads.size(); i++) {
  Thread justJoined = join.joinNextThread();
  System.out.println("Done with a thread, just joined=" + justJoined);
}

和来源:

public static class JoinThreads {
  java.util.concurrent.LinkedBlockingQueue<Thread> doneThreads = 
      new LinkedBlockingQueue<Thread>();

  public JoinThreads(List<Thread> threads) {
    for(Thread t : threads) {
      final Thread joinThis = t;
      new Thread(new Runnable() {
        @Override
        public void run() {
          try {
            joinThis.join();
            doneThreads.add(joinThis);
          }
          catch (InterruptedException e) {
            // "should" never get here, since we control this thread and don't call interrupt on it
          }
        }
      }).start();
    }

  }

  Thread joinNextThread() throws InterruptedException {
    return doneThreads.take();
  }
}

这样做的好处是它可以与通用 Java 线程一起使用,无需修改,任何线程都可以加入。需要注意的是,它需要一些额外的线程创建。如果您没有完整地调用 joinNextThread() 并且没有“关闭”方法等,这个特定的实现也会“留下线程”。如果您想要创建更精美的版本,请在此处发表评论。您也可以将这种相同类型的模式与“期货”而不是线程对象等一起使用。

2021-10-16T06:38:52   回复