45

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.

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?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
A Jackson
  • 2,776
  • 7
  • 34
  • 45
  • Possible duplicate of [How to wait for a set of threads to complete?](http://stackoverflow.com/questions/1252190/how-to-wait-for-a-set-of-threads-to-complete) – Ravindra babu May 11 '16 at 15:51

5 Answers5

77

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

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, this seems to work, had to refactor my code a little to get the thread references in my cleanup method but I think it is working. It is running now, just takes a few minutes. – A Jackson Sep 01 '09 at 07:50
  • Just completed testing it. Worked perfectly. – A Jackson Sep 01 '09 at 07:58
  • 16
    @Jon Skeet, I have one doubt. line `thread.join();` will make current process to wait till thread `thread` is running,right? then what will happen here is, main process will come to 2nd line and will wait for `thread` to finish its work, then it will go for next `thread` in loop, so actually main will wait till 1st child thread is running, then it will execute `thread.join()` for next thread, am I right? – Patriks Feb 06 '13 at 06:25
  • 1
    @Pratik: It will block the current *thread* (not process) until `thread` has finished (not started). The expectation is that all of the threads are already running before the code in my answer executes... it just waits for each of them to *finish*. – Jon Skeet Feb 06 '13 at 06:59
  • 5
    @Jon skeet, please make me clear, I understand that if a thread main is calling thread.join() then main thread will be paused, and main will resume when thread `thread` has finished. Am I getting it right? now, say there are 3 threads in variable `threads` so `for` loop will execute 3 times, 1st time for 1st `thread` main will execute `.join()` then it will be in paused by system and will be resumed when 1st thread has finished. then only it can go again in loop for next (2nd) thread element. Am I getting it right? – Patriks Feb 06 '13 at 07:18
  • @Pratik: Yes, that's basically it. – Jon Skeet Feb 06 '13 at 07:22
  • 9
    Another point to note is that by the time the main thread moves to join second thread, it might have already completed. In this case joining that will return immediately. So, main thread will then move on to join the third thread. – AppleGrew Jan 03 '15 at 08:37
  • What happens if one of the threads throw `InerruptedExpception` or something else? Won't that mean the remaining threads never get joined? – Thomas Ahle Aug 13 '19 at 10:36
  • 1
    @ThomasAhle: Yes, it would - often exiting immediately is the right thing to do; other times you'd want to handle that differently. – Jon Skeet Aug 13 '19 at 10:51
15

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.

Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
15

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.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Kenster
  • 23,465
  • 21
  • 80
  • 106
  • 1
    Surprisingly, this is really the best way to go. It allows you to use multiple threads but maintain a limited number of threads, perhaps based on the number of cores on the device. – Joshua Pinter Jul 12 '19 at 05:56
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.

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
2

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.

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.

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.

Community
  • 1
  • 1
rogerdpack
  • 62,887
  • 36
  • 269
  • 388