views:

320

answers:

6

In my program, I am creating several threads in the main() method. The last line in the main method is a call to System.out.println(), which I don't want to call until all the threads have died. I have tried calling Thread.join() on each thread however that blocks each thread so that they execute sequentially instead of in parallel.

Is there a way to block the main() thread until all other threads have finished executing? Here is the relevant part of my code:

public static void main(String[] args) {

//some other initialization code

//Make array of Thread objects
Thread[] racecars = new Thread[numberOfRaceCars];

//Fill array with RaceCar objects
for(int i=0; i<numberOfRaceCars; i++) {
    racecars[i] = new RaceCar(laps, args[i]);
}

//Call start() on each Thread
for(int i=0; i<numberOfRaceCars; i++) {
    racecars[i].start();
    try {
        racecars[i].join(); //This is where I tried to using join()
                            //It just blocks all other threads until the current                            
                            //thread finishes.
    } catch(InterruptedException e) {
        e.printStackTrace();
    }
}

//This is the line I want to execute after all other Threads have finished
System.out.println("It's Over!");

}

Thanks for the help guys!

Eric

+1  A: 

You could wait() in your main thread and have all threads issue a notifyAll() when they're done. Then each time your main thread gets woken up that way, it can check if there's at least one thread that's still alive in which case you wait() some more.

Thomas
I'm still learning Java programming so I don't completely understand synchronization and object monitors yet. I'll investigate this. Thanks!
thechiman
@thechiman - if you have some spare time at your hands, you may also want to study the java.util.concurrent package which provides some pretty powerful ways for concurrency beyond "low-level" Threads.
Thomas
I'll check that out too. Thanks.
thechiman
-1 - this approach is way too complicated ... and far too easy to get wrong, leading to hours of "fun" debugging.
Stephen C
The example in the book (Raposa, 2003) that I'm learning from that uses wait() and notify() is extremely confusing. The code associated with it doesn't work as it is either. I'll have to go elsewhere for text that will explain this for me.
thechiman
+11  A: 

You start your threads and immediately wait for them to be finished (using join()). Instead, you should do the join() outside of the for-loop in another for-loop, e.g.:

// start all threads
for(int i=0; i<numberOfRaceCars; i++) {
    racecars[i].start();
}
// threads run... we could yield explicity to allow the other threads to execute
// before we move on, all threads have to finish
for(int i=0; i<numberOfRaceCars; i++) {
    racecars[i].join(); // TODO Exception handling
}
// now we can print
System.out.println("It's over!");
middus
Nice, that worked beautifully! Thanks!
thechiman
This is obviously the right way to go. I can't believe the other answers that advocate the use of wait() and notify() and barriers were upvoted: they're far too complicated for this situation.
Adrian Pronk
@AdrianPronk: That's the beauty of different opinions.
Thomas
@AdrianPronk: maybe these people read *"Effective Java"* and *"Java Concurrency In Practice"* and preferred to go with higher level abstractions (that also translate more easily to other language), that have less gotchas, as advocated in these two gorgeous books? On my desk, a paragraph from CJIP: *"This is a flaw in the Thread API, because wether or not the join completes successfully has memory visibility consequences in the Java Memory Model, but join does not return a status indicating whether it was successful"*. Don't get me started, I've got a lot of appeal to authority on my side ;)
Webinator
@AdrianPonk: in addition to that implementing, say, a *CountDownLatch* and (a)waiting for the threads to count it down takes royally **3** lines of code. Don't make it sound like it's a bad solution, because it's not.
Webinator
@WizardOfOdds - I think the book is mostly referring to wait / notify synchronization, which is notoriously easy to stuff up. By contrast, using Thread.join in a master thread is hard to stuff up.
Stephen C
@WizardOfOdds: I agree that JCIP et al are excellent books. I have read them and loved them, but what about KISS? OP's question has a simple answer: kudos to @middus for providing it. The other answers go beyond the question and I think they should only be offered in the spirit of "further reading if OP is curious". BTW, your quote from JCIP regards timed join and is not relevant in this context.
Adrian Pronk
A: 

You could make the last line be in a "monitoring" thread. It would check every so often that it is the only running thread and some completion state == true and then could fire if it was. Then it could do other things than just println

Smalltown2000
A: 

You can use the join method. Refer to the documentation here

Dan
He already uses join.
middus
+3  A: 

You could share a CyclicBarrier object among your RaceCars and your main thread, and have the RaceCar threads invoke await() as soon as they are done with their task. Construct the barrier with the number of RaceCar threads plus one (for the main thread). The main thread will proceed when all RaceCars have finished. See http://java.sun.com/javase/6/docs/api/java/util/concurrent/CyclicBarrier.html

In detail, construct a CyclicBarrier in the main thread, and add a barrier.await() call in your RaceCar class just before the run() method exits, also add a barrier.await() call before the System.out.println() call in your main thread.

I'll check this out too, thanks for the help.
thechiman
Just saw that Java has a class called "java.util.concurrent.CountDownLatch" dedicated to such a problem, which works similar to the barrier, but allows the finished car threads to exit immediately when they're done by offering a method called "countDown()".
@the-banana-king: +1... The advantage of cyclic barriers and/or count down latches etc. are that they're well known concurrency techniques and *not* Java idiosynchrasies requiring deep knowledge of uninteresting Java specificities. Books like *"Java Concurrency in Practice"* recommend to avoid low-level (Java) details and go for higher-level abstractions/solutions.
Webinator
A: 

You can add a shutdown hook for the "Its Over" message. This way it will be produced when the program finishes and you don't have to wait for each thread.

Peter Lawrey