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(I开发者_JAVA百科nterruptedException 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
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!");
You could share a CyclicBarrier
object among your RaceCar
s 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 RaceCar
s 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.
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.
You can use the join method. Refer to the documentation here
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.
You have better options if you go for ExecutorService or ThreadPoolExecutor framework.
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:
CountDownLatch : Initialize CountDownLatch with counter as number of threads. Use
countDown()
andawait()
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?
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
Simplest way
while (Thread.activeCount() > 1) {
}
I know it block main thread... but it works perfectly!
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
}
}
}
精彩评论