等待多个线程在Java中完成

时间:2021-05-28 20:54:27

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. 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.

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

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?

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

Thanks.

5 个解决方案

#1


52  

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做一些事情,你可能希望在出现问题时提供超时,但这是基本的想法...)

#2


14  

If you are using java 1.5 or higher, you can try 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.

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

#3


8  

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来实现多个线程之间的任意集合点。

#4


5  

Have you seen the Executor classes in java.util.concurrent? You could run your threads through an ExecutorService. It gives you a single object you can use to cancel the threads or wait for them to complete.

你在java.util.concurrent中看过Executor类吗?您可以通过ExecutorService运行您的线程。它为您提供了一个可用于取消线程或等待它们完成的对象。

#5


1  

If you control the creation of the Threads (submission to an ExecutorService) then it appears you can use an ExecutorCompletionService see ExecutorCompletionService? Why do need one if we have invokeAll? for various answers there.

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

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. Basically by newing up "watching threads" which alert when the other threads terminate, you can know when the "next" thread out of many terminates.

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

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. 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. You could also use this same type of pattern with "Futures" instead of Thread objects, etc.

这很好的部分是它适用于通用Java线程,无需修改,任何线程都可以连接。需要注意的是,它需要一些额外的线程创建。如果你没有多次调用joinNextThread(),并且没有“close”方法等,那么这个特殊的实现“会留下线程”。如果你想要创建一个更精美的版本,请在此处注释。您也可以将这种类型的模式与“Futures”一起使用,而不是使用Thread对象等。

#1


52  

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做一些事情,你可能希望在出现问题时提供超时,但这是基本的想法...)

#2


14  

If you are using java 1.5 or higher, you can try 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.

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

#3


8  

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来实现多个线程之间的任意集合点。

#4


5  

Have you seen the Executor classes in java.util.concurrent? You could run your threads through an ExecutorService. It gives you a single object you can use to cancel the threads or wait for them to complete.

你在java.util.concurrent中看过Executor类吗?您可以通过ExecutorService运行您的线程。它为您提供了一个可用于取消线程或等待它们完成的对象。

#5


1  

If you control the creation of the Threads (submission to an ExecutorService) then it appears you can use an ExecutorCompletionService see ExecutorCompletionService? Why do need one if we have invokeAll? for various answers there.

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

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. Basically by newing up "watching threads" which alert when the other threads terminate, you can know when the "next" thread out of many terminates.

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

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. 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. You could also use this same type of pattern with "Futures" instead of Thread objects, etc.

这很好的部分是它适用于通用Java线程,无需修改,任何线程都可以连接。需要注意的是,它需要一些额外的线程创建。如果你没有多次调用joinNextThread(),并且没有“close”方法等,那么这个特殊的实现“会留下线程”。如果你想要创建一个更精美的版本,请在此处注释。您也可以将这种类型的模式与“Futures”一起使用,而不是使用Thread对象等。