24

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

ericso
  • 3,218
  • 7
  • 29
  • 36

9 Answers9

48

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
  • 9,103
  • 1
  • 31
  • 33
  • 3
    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 Mar 12 '10 at 22:23
  • @AdrianPronk: That's the beauty of different opinions. – Thomas Mar 12 '10 at 22:31
  • @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 ;) – SyntaxT3rr0r Mar 12 '10 at 23:19
  • 1
    @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. – SyntaxT3rr0r Mar 12 '10 at 23:23
  • @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 Mar 13 '10 at 03:49
  • 1
    @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 Mar 13 '10 at 10:24
  • Is there a way to do this if we're using Runnable? Since I can't user `join()` – SaintLike Dec 16 '14 at 15:47
6

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.

the-banana-king
  • 509
  • 2
  • 9
  • 1
    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 Mar 12 '10 at 22:21
  • @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. – SyntaxT3rr0r Mar 12 '10 at 23:12
2

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
  • 17,016
  • 4
  • 46
  • 70
  • I'm still learning Java programming so I don't completely understand synchronization and object monitors yet. I'll investigate this. Thanks! – ericso Mar 12 '10 at 22:02
  • 1
    @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 Mar 12 '10 at 22:04
  • -1 - this approach is way too complicated ... and far too easy to get wrong, leading to hours of "fun" debugging. – Stephen C Mar 13 '10 at 03:44
  • 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. – ericso Mar 13 '10 at 17:22
  • @StephenC Rereading my own answer now, I completely agree. What was I thinking?... – Thomas Mar 04 '14 at 09:31
1

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

Dan
  • 1,763
  • 4
  • 26
  • 40
1

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
  • 525,659
  • 79
  • 751
  • 1,130
1

You have better options if you go for ExecutorService or ThreadPoolExecutor framework.

  1. invokeAll

    Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list. Note that a completed task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress. Type Parameters:

  2. CountDownLatch : Initialize CountDownLatch with counter as number of threads. Use countDown() and await() APIs and wait for counter to become zero.

Further references:

How to use invokeAll() to let all thread pool do their task?

How is CountDownLatch used in Java Multithreading?

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

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

Smalltown2k
  • 811
  • 8
  • 13
0

Simplest way

while (Thread.activeCount() > 1) {
}

I know it block main thread... but it works perfectly!

0

Try This example:

public class JoinTest extends Thread { 

    public static void main(String[] args) 
    {
        JoinTest t = new JoinTest();
        t.start();

        try {

            t.join();
            int i = 0;
            while(i<5)
            {
                System.out.println("parent thread is running......" +i++);
            }

        } catch (Exception e) {
            // TODO: handle exception
        }


    }


    public void run()
    {

        try {

            int i =0;
            while(i<5)
            {
                System.out.println("child thread running ........." +i++);
            }

        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}
agold
  • 6,140
  • 9
  • 38
  • 54
user1668782
  • 179
  • 1
  • 11
  • Please explain why this should work, see [how to answer](http://stackoverflow.com/help/how-to-answer). – agold Feb 15 '16 at 08:12