在Java中等待多个线程完成

在Java中等待多个线程完成,java,multithreading,synchronization,Java,Multithreading,Synchronization,在我的程序执行过程中,启动了许多线程。线程的数量因用户定义的设置而异,但它们都使用不同的变量执行相同的方法 在某些情况下,在执行过程中需要进行清理,其中一部分是停止所有线程,但我不希望它们立即停止,我只是设置了一个变量,让它们检查以终止它们。问题是,在线程停止之前,它可能长达1/2秒。但是,我需要确保所有线程都已停止,然后才能继续清理。清理是从另一个线程执行的,所以技术上我需要这个线程等待其他线程完成 我已经想到了几种方法,但它们似乎都过于复杂。我希望有一些方法可以等待一组线程完成。有这样的事吗

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

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

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


谢谢。

一个接一个地加入他们吧:

for (Thread thread : threads) {
  thread.join();
}
(您需要对InterruptedException执行一些操作,并且您可能希望在出现问题时提供一个超时,但这是基本想法…

自己定义一个实用方法:

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

或者,您可以在
java.util.concurrent
库中使用
CyclicBarrier
来实现多个线程之间的任意集合点。

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

您是否在
java.util.concurrent
中看到了
Executor
类?您可以通过执行器服务运行线程。它为您提供了一个对象,您可以使用它来取消线程或等待线程完成。

如果您控制线程的创建(提交给ExecutorService),那么您似乎可以使用
ExecutorCompletionService
请参阅此处的各种答案

如果您不控制线程的创建,这里有一种方法可以让您“在线程完成时一个接一个地”加入线程(并知道哪个线程先完成,等等),这是受ruby类启发的。 基本上,通过更新“监视线程”,当其他线程终止时发出警报,您可以知道多个线程中的“下一个”线程何时终止

你可以这样使用它:

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);
}
JoinThreads join=新的JoinThreads(线程);
对于(int i=0;i
资料来源:

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();
  }
}
公共静态类JoinThreads{
java.util.concurrent.LinkedBlockingQueue doneThreads=
新建LinkedBlockingQueue();
公共连接线程(列出线程){
用于(螺纹t:螺纹){
最终螺纹接头this=t;
新线程(newrunnable()){
@凌驾
公开募捐{
试一试{
joinThis.join();
添加(joinThis);
}
捕捉(中断异常e){
//“应该”永远不会到达这里,因为我们控制这个线程,不调用它的中断
}
}
}).start();
}
}
线程joinNextThread()抛出InterruptedException{
返回doneThreads.take();
}
}

这其中很好的一点是,它可以与通用Java线程一起工作,无需修改,任何线程都可以连接。需要注意的是,它需要一些额外的线程创建。此外,如果调用joinNextThread()的次数不完整,并且没有“close”方法等,则此特定实现会“留下线程”。如果希望创建更完善的版本,请在此处进行注释。您也可以将这种类型的模式与“Futures”一起使用,而不是线程对象等等。

谢谢,这似乎可以满足我的要求,但当我看到这一点时,已经写好了Jon的答案。如果您只做一次,另一种方法是使用CountdownLatch。@Jon Skeet,我有一个疑问。line
thread.join()
将使当前进程等待线程
线程
运行,对吗?然后这里将发生的是,主进程将到达第二行,并等待
线程完成其工作,然后它将进入循环中的下一个
线程,所以实际上main将等待第一个子线程运行,然后它将为下一个线程执行
线程.join()
,我说的对吗?@Pratik:它将阻止当前线程(不是进程),直到
线程
完成(不是启动)。我们的期望是,在我的答案中的代码执行之前,所有线程都已经在运行了。。。它只是等待它们中的每一个都完成。@Jon skeet,请澄清一下,我知道如果一个线程main正在调用thread.join(),那么主线程将暂停,当thread
thread
完成时,main将恢复。我说得对吗?现在,假设变量
threads
中有3个线程,那么
for
循环将执行3次,第1个
thread
main的第1次将执行
。join()
然后系统将暂停它,并在第一个线程完成后恢复。然后,只有它才能再次进入下一个(第二个)线程元素的循环。我说得对吗?另一点需要注意的是,当主线程移动到加入第二个线程时,它可能已经完成了。在这种情况下,将立即返回。因此,主线程将继续连接第三个线程。@ThomasAhle:是的,它会-通常立即退出是正确的做法;其他时候你可能会想用不同的方式来处理。令人惊讶的是,这确实是最好的方法。它允许您使用多个线程,但保持有限的线程数,可能是基于设备上的内核数。
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();
  }
}