How to wait for a number of threads to complete?

177,222

Solution 1

You put all threads in an array, start them all, and then have a loop

for(i = 0; i < threads.length; i++)
  threads[i].join();

Each join will block until the respective thread has completed. Threads may complete in a different order than you joining them, but that's not a problem: when the loop exits, all threads are completed.

Solution 2

One way would be to make a List of Threads, create and launch each thread, while adding it to the list. Once everything is launched, loop back through the list and call join() on each one. It doesn't matter what order the threads finish executing in, all you need to know is that by the time that second loop finishes executing, every thread will have completed.

A better approach is to use an ExecutorService and its associated methods:

List<Callable> callables = ... // assemble list of Callables here
                               // Like Runnable but can return a value
ExecutorService execSvc = Executors.newCachedThreadPool();
List<Future<?>> results = execSvc.invokeAll(callables);
// Note: You may not care about the return values, in which case don't
//       bother saving them

Using an ExecutorService (and all of the new stuff from Java 5's concurrency utilities) is incredibly flexible, and the above example barely even scratches the surface.

Solution 3

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class DoSomethingInAThread implements Runnable
{
   public static void main(String[] args) throws ExecutionException, InterruptedException
   {
      //limit the number of actual threads
      int poolSize = 10;
      ExecutorService service = Executors.newFixedThreadPool(poolSize);
      List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();

      for (int n = 0; n < 1000; n++)
      {
         Future f = service.submit(new DoSomethingInAThread());
         futures.add(f);
      }

      // wait for all tasks to complete before continuing
      for (Future<Runnable> f : futures)
      {
         f.get();
      }

      //shut down the executor service so that this thread can exit
      service.shutdownNow();
   }

   public void run()
   {
      // do something here
   }
}

Solution 4

instead of join(), which is an old API, you can use CountDownLatch. I have modified your code as below to fulfil your requirement.

import java.util.concurrent.*;
class DoSomethingInAThread implements Runnable{
    CountDownLatch latch;
    public DoSomethingInAThread(CountDownLatch latch){
        this.latch = latch;
    } 
    public void run() {
        try{
            System.out.println("Do some thing");
            latch.countDown();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

public class CountDownLatchDemo {
    public static void main(String[] args) {
        try{
            CountDownLatch latch = new CountDownLatch(1000);
            for (int n=0; n<1000; n++) {
                Thread t = new Thread(new DoSomethingInAThread(latch));
                t.start();
            }
            latch.await();
            System.out.println("In Main thread after completion of 1000 threads");
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

Explanation:

  1. CountDownLatch has been initialized with given count 1000 as per your requirement.

  2. Each worker thread DoSomethingInAThread will decrement the CountDownLatch, which has been passed in constructor.

  3. Main thread CountDownLatchDemo await() till the count has become zero. Once the count has become zero, you will get below line in output.

    In Main thread after completion of 1000 threads
    

More info from oracle documentation page

public void await()
           throws InterruptedException

Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.

Refer to related SE question for other options:

wait until all threads finish their work in java

Solution 5

Avoid the Thread class altogether and instead use the higher abstractions provided in java.util.concurrent

The ExecutorService class provides the method invokeAll that seems to do just what you want.

Share:
177,222
DivideByHero
Author by

DivideByHero

Updated on December 23, 2021

Comments

  • DivideByHero
    DivideByHero over 2 years

    What is a way to simply wait for all threaded process to finish? For example, let's say I have:

    public class DoSomethingInAThread implements Runnable{
    
        public static void main(String[] args) {
            for (int n=0; n<1000; n++) {
                Thread t = new Thread(new DoSomethingInAThread());
                t.start();
            }
            // wait for all threads' run() methods to complete before continuing
        }
    
        public void run() {
            // do something here
        }
    
    
    }
    

    How do I alter this so the main() method pauses at the comment until all threads' run() methods exit? Thanks!

  • Martin v. Löwis
    Martin v. Löwis over 14 years
    Not sure how you exactly propose to do it. If you propose to poll activeCount in a loop: that's bad, since it's busy-wait (even if you sleep between polls - you then get a tradeoff between business and responsiveness).
  • Martin K.
    Martin K. over 14 years
    ThreadGroup is the way to go! With a mutable List you'll get in trouble (synchronisation)
  • Martin v. Löwis
    Martin v. Löwis over 14 years
    @Mykola: what exactly is the advantage of using a thread group? Just because the API is there doesn't mean you have to use it...
  • DivideByHero
    DivideByHero over 14 years
    Thanks guys. I will look into ThreadGroup, but using join() seems so much simpler for working with existing code!
  • Adam Batkin
    Adam Batkin over 14 years
    What? How would you get in trouble? It's only mutable (only readble) by the thread that is doing the launching, so as long as it doesn't modify the list while iterating through it, it's fine.
  • Martin K.
    Martin K. over 14 years
    See: "A thread group represents a set of threads." This is semantic correct for this use-case! And: "A thread is allowed to access information about its own thread group"
  • Martin K.
    Martin K. over 14 years
    It depends on how you use it. If you'll use the calling class in a thread you'll have problems.
  • Martin v. Löwis
    Martin v. Löwis over 14 years
    @Martin K: A variable of type Thread[] or ArrayList<Thread> also represents a group of threads. There are many ways to represent a group of threads; in general, container types are best if you want to iterate over elements. For the specific problem, it is not relevant that a thread knows its thread group. So this entire thread group API is artificial, and useless for the problem at hand.
  • Bastien Léonard
    Bastien Léonard over 14 years
    The book “Effective Java” recommends avoiding thread groups (item 73).
  • Martin K.
    Martin K. over 14 years
    The bugs mentioned in Effective Java should have been fixed in Java 6. If newer java versions aren't a restriction, it's better to use Futures to solve thread problems. Martin v. Löwis: You're right. It's not relecant for that problem, but it's nice to get more Information about the running threads from one Object (like the ExecutorService). I think it's nice to use given features to solve a problem; maybe you'll need more flexibility (thread information) in the future. It's also right to mention the old buggy classes in older JDKs.
  • Admin
    Admin over 14 years
    ThreadGroup does not implement a group-level join, so why people are pushing ThreadGroup is a little baffling. Are people really using spin locks & querying the group's activeCount? You'd be hard-pressed to convince me that doing so it better in any way when compared to just calling join on all of the threads.
  • Pablo Cavalieri
    Pablo Cavalieri over 9 years
    Is a latch for threads, the latch lock works with a countdown. In the run() method of your thread explicitly declare to wait for a CountDownLatch to reach it's countdown to 0. You can use the same CountDownLatch in more than one thread to release them simultaneously. I don't know if it is what you need, just wanted to mention it because it's useful when working in a multithread environment.
  • Russia Must Remove Putin
    Russia Must Remove Putin over 9 years
    Maybe you should put that explanation in the body of your answer?
  • Pablo Cavalieri
    Pablo Cavalieri over 9 years
    The examples in the Javadoc are very descriptive, that's why I didn't add any. docs.oracle.com/javase/7/docs/api/java/util/concurrent/…. In the first example, all the Workers threads are releases simultaneously because they wait for the CountdownLatch startSignal to reach zero, which happens in startSignal.countDown(). Then, the mian thread waits until all the workes finish using the instruction doneSignal.await(). doneSignal decrease its value in each worker.
  • arn-arn
    arn-arn about 8 years
    worked like a charm... i have two sets of threads which should not run simultaneously because of issues on multiple cookies. I used your example to run one set of threads at a time.. thanks for sharing your knowledge...
  • Ruchir Baronia
    Ruchir Baronia about 8 years
    Hi, it didn't work for me for some reason. Here is my question: stackoverflow.com/users/5144855/ruchir-baronia
  • Ruchir Baronia
    Ruchir Baronia about 8 years
    Hi, it didn't work for me for some reason. Here is my question: stackoverflow.com/users/5144855/ruchir-baronia
  • jt.
    jt. almost 8 years
    @Dantalian - In your Runnable class (likely in the run method), you would want to capture any exceptions that occurred and store them locally (or store an error message/condition). In the example, f.get() returns your object that you submitted to the ExecutorService. Your object could have a method for retrieving any exceptions/error conditions. Depending on how you modify the provided example, you might need to cast the object turned by f.get() to your expected type.
  • Admin
    Admin almost 8 years
    What if main() is midway interrupted, how do you cleanup the started threads?
  • Guenther
    Guenther over 7 years
    I don't think that is is a good example for CyclicBarrier. Why do you use a Thread.sleep() call?
  • shailendra1118
    shailendra1118 over 7 years
    @Guenther - yes, I changed the code to suite the requirement.
  • Elysiumplain
    Elysiumplain almost 7 years
    CyclicBarrier is not an alternative to CountDownLatch. When threads must repeatedly count down you should create a CyclicBarrier, otherwise default to CountDownLatch (unless otherwise requiring additional abstraction of Execution, at which point you should look to the higher-level, Services).