Как приостановить main(), пока все другие потоки не умерли?
В моей программе я создаю несколько потоков в методе main(). Последняя строка в основном методе - это вызов System.out.println(), который я не хочу вызывать до тех пор, пока все потоки не погибнут. Я попытался вызывать Thread.join() для каждого потока, но блокирует каждый поток так, чтобы они выполнялись последовательно, а не параллельно.
Есть ли способ заблокировать поток main(), пока все остальные потоки не закончатся? Вот соответствующая часть моего кода:
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 Over!");
}
Спасибо за помощь ребятам!
Эрик
Ответы
Ответ 1
Вы запускаете свои потоки и немедленно ждете их завершения (используя join()
). Вместо этого вы должны сделать join()
вне цикла for-loop в другом for-loop, например:
// 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 over!");
Ответ 2
Вы можете поделиться объектом CyclicBarrier
среди вашего RaceCar
и основного потока, а потоки RaceCar
вызывать await()
, как только они будут выполнены с их задачей. Постройте барьер с количеством потоков RaceCar
плюс один (для основного потока). Основной поток будет продолжаться, когда все RaceCar
закончатся.
См. http://java.sun.com/javase/6/docs/api/java/util/concurrent/CyclicBarrier.html
Подробно постройте CyclicBarrier
в главном потоке и добавьте вызов barrier.await()
в свой RaceCar
класс перед тем, как метод run()
завершится, также добавьте вызов barrier.await()
перед System.out.println()
звоните в основной поток.
Ответ 3
Вы могли бы wait()
в своем основном потоке и все потоки вывести notifyAll()
, когда они будут сделаны. Затем каждый раз, когда ваш основной поток проснется таким образом, он может проверить, есть ли хотя бы один поток, который все еще жив, в этом случае вы wait()
еще немного.
Ответ 4
Вы можете использовать метод объединения. См. Документацию здесь
Ответ 5
Вы можете добавить крюк отключения для сообщения "Сверху". Таким образом, он будет создан, когда программа закончится, и вам не придется ждать каждого потока.
Ответ 6
Вы можете сделать последнюю строку в "контрольном" потоке. Он будет проверять каждый так часто, что это единственный текущий поток и некоторое состояние завершения == true
, а затем может срабатывать, если это так. Тогда он мог бы делать другие вещи, чем просто println
Ответ 7
Простейший способ
while (Thread.activeCount() > 1) {
}
Я знаю, что он блокирует основной поток... но он отлично работает!
Ответ 8
Попробуйте этот пример:
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
}
}
}
Ответ 9
У вас есть лучшие варианты, если вы перейдете на ExecutorService или ThreadPoolExecutor.
Другие ссылки:
Как использовать invokeAll(), чтобы все пулы потоков выполняли свою задачу?
Как используется CountDownLatch в многопоточности Java?