简体   繁体   English

在 Java 中等待多个线程完成

[英]Waiting on multiple threads to complete in Java

During the course of my program execution, a number of threads are started.在我的程序执行过程中,启动了许多线程。 The amount of threads varies depending on user defined settings, but they are all executing the same method with different variables.线程的数量取决于用户定义的设置,但它们都在执行具有不同变量的相同方法。

In some situations, a clean up is required mid execution, part of this is stopping all the threads, I don't want them to stop immediately though, I just set a variable that they check for that terminates them.在某些情况下,需要在执行过程中进行清理,其中一部分是停止所有线程,但我不希望它们立即停止,我只是设置了一个他们检查的变量来终止它们。 The problem is that it can be up to 1/2 second before the thread stops.问题是在线程停止之前最多可能需要 1/2 秒。 However, I need to be sure that all threads have stopped before the clean up can continues.但是,我需要确保所有线程都已停止,然后才能继续进行清理。 The cleanup is executed from another thread so technically I need this thread to wait for the other threads to finish.清理是从另一个线程执行的,所以从技术上讲,我需要这个线程等待其他线程完成。

I have thought of several ways of doing this, but they all seem to be overly complex.我已经想到了几种方法来做到这一点,但它们似乎都过于复杂。 I was hoping there would be some method that can wait for a group of threads to complete.我希望有一些方法可以等待一组线程完成。 Does anything like this exist?这样的事情存在吗?

Just join them one by one: 只需逐个加入:

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

(You'll need to do something with InterruptedException , and you may well want to provide a time-out in case things go wrong, but that's the basic idea...) (你需要用InterruptedException做一些事情,你可能希望在出现问题时提供超时,但那是基本的想法...)

If you are using java 1.5 or higher, you can try CyclicBarrier . 如果您使用的是Java 1.5或更高版本,则可以尝试使用CyclicBarrier You can pass the cleanup operation as its constructor parameter, and just call barrier.await() on all threads when there is a need for cleanup. 您可以将清理操作作为其构造函数参数传递,并在需要清理时在所有线程上调用barrier.await()

Have you seen the Executor classes in java.util.concurrent ? 你在java.util.concurrent看过Executor类吗? You could run your threads through an ExecutorService . 您可以通过ExecutorService运行您的线程。 It gives you a single object you can use to cancel the threads or wait for them to complete. 它为您提供了一个可用于取消线程或等待它们完成的对象。

Define a utility method (or methods) yourself: 自己定义一种实用方法(或多种方法):

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

Or you may have an array 或者你可能有一个阵列

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

Alternatively you could look at using a CyclicBarrier in the java.util.concurrent library to implement an arbitrary rendezvous point between multiple threads. 或者,您可以查看在java.util.concurrent库中使用CyclicBarrier来实现多个线程之间的任意集合点。

If you control the creation of the Threads (submission to an ExecutorService) then it appears you can use an ExecutorCompletionService see ExecutorCompletionService? 如果你控制Threads的创建(提交给ExecutorService),那么看来你可以使用ExecutorCompletionServiceExecutorCompletionService吗? Why do need one if we have invokeAll? 如果我们有invokeAll,为什么需要一个? for various answers there. 在那里有各种答案。

If you don't control thread creation, here is an approach that allows you to join the threads "one by one as they finish" (and know which one finishes first, etc.), inspired by the ruby ThreadWait class. 如果你不控制线程创建,这里有一种方法,允许你在ruby ThreadWait类的启发下“逐个完成”加入线程(并知道哪一个完成,等等)。 Basically by newing up "watching threads" which alert when the other threads terminate, you can know when the "next" thread out of many terminates. 基本上通过新建“监视线程”,当其他线程终止时,它会发出警告,你可以知道多个“下一个”线程何时终止。

You'd use it something like this: 你会用这样的东西:

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);
}

And the source: 来源:

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();
  }
}

The nice part of this is that it works with generic Java threads, without modification, any thread can be joined. 这很好的部分是它适用于通用Java线程,无需修改,任何线程都可以连接。 The caveat is it requires some extra thread creation. 需要注意的是,它需要一些额外的线程创建。 Also this particular implementation "leaves threads behind" if you don't call joinNextThread() the full number of times, and doesn't have an "close" method, etc. Comment here if you'd like a more polished version created. 如果你没有多次调用joinNextThread(),并且没有“关闭”方法等,这个特殊的实现“会留下线程”。如果你想要创建一个更精美的版本,请在此处注释。 You could also use this same type of pattern with "Futures" instead of Thread objects, etc. 您也可以将这种类型的模式与“Futures”一起使用,而不是使用Thread对象等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM