views:

788

answers:

8

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!

A: 

You can do it with the Object "ThreadGroup" and its parameter activeCount:

Martin K.
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 v. Löwis
@Martin v. Löwis: "Join will wait for just a single thread. A better solution might be ajava.util.concurrent.CountDownLatch. Simply initialize the latch withthe count set to the number of worker threads. Each worker threadshould call countDown() just before it exits, and the main threadsimply calls await(), which will block until the counter reaches zero. The problem with join() is also that you can't start adding more threads dynamically. The list will explode with a ConcurrentModification." Your solution works fine for the Problem but not for general purpose.
Martin K.
+3  A: 

If you make a list of the threads, you can loop through them and .join() against each, and your loop will finish when all the threads have. I haven't tried it though.

http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#join()

David
+8  A: 

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.

Martin v. Löwis
Thread group is more natural way to do this since Java 5.
Mykola Golubyev
@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...
Martin v. Löwis
Thanks guys. I will look into ThreadGroup, but using join() seems so much simpler for working with existing code!
ZenBlender
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: 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.
Martin v. Löwis
The book “Effective Java” recommends avoiding thread groups (item 73).
Bastien Léonard
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.
Martin K.
+5  A: 

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();
// 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.

Adam Batkin
ThreadGroup is the way to go! With a mutable List you'll get in trouble (synchronisation)
Martin K.
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.
Adam Batkin
It depends on how you use it. If you'll use the calling class in a thread you'll have problems.
Martin K.
++ for ExecutorService
Martin K.
+2  A: 

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.

henrik
+1  A: 

This would be a comment, but I can't do comments yet.

Martin K, I'm curious about how you'd use ThreadGroup. Have you done so before?

I see that above, you suggest checking activeCount - setting aside Martin v Löwis's concern about polling aside for the moment, I have another concern with activeCount itself.

Caveat: I haven't tried using this, so I'm no expert on the matter, but according to the javadocs, it returns an estimate of the number of active threads.

Personally, I'd be loathe to try and build a system on an estimate. Do you have another thought on how to do it, or am I misreading the javadoc?

CPerkins
The value returned is only an estimate because the number of threads may change dynamically while this method traverses internal data structures, and might be affected by the presence of certain system threads. It should be okay for monitoring purposes.
Martin K.
This is always an issue in threaded environments! Do you really want to lock every thread to get a "better" value?
Martin K.
Martin, I agree that an estimate for number of active threads is fine for a monitor process. But unless I misread, the OP wanted to wait until all were complete - which doesn't sound like a monitor. To me, there's a significant difference between knowing they're all complete, and thinking they're all complete (which is the best you can do, relying on an estimate).However, your CountDownLatch idea is excellent.
CPerkins
+1  A: 

Depending on your needs, you may also want to check out the classes CountDownLatch and CyclicBarrier in the java.util.concurrent package. They can be useful if you want your threads to wait for each other, or if you want more fine-grained control over the way your threads execute (e.g., waiting in their internal execution for another thread to set some state). You could also use a CountDownLatch to signal all of your threads to start at the same time, instead of starting them one by one as you iterate through your loop. The standard API docs have an example of this, plus using another CountDownLatch to wait for all threads to complete their execution.

Jeff
+2  A: 
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
   }
}
jt