Как мне приостановить main(), пока все остальные потоки не прекратятся?

В моей программе я создаю несколько потоков в методе 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's Over!");

}

Спасибо за помощь, ребята!

Эрик

9 ответов

Решение

Вы запускаете свои темы и сразу ждете их завершения (используя join()). Вместо этого вы должны сделать join() вне цикла for в другом цикле for, например:

// 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!");

Вы могли бы поделиться 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() позвоните в ваш главный поток.

Вы могли бы wait() в вашей основной теме, и все темы выдают notifyAll() когда они закончат Затем каждый раз, когда ваш основной поток пробуждается таким образом, он может проверить, существует ли хотя бы один поток, который еще жив, и в этом случае вы wait() еще немного.

Вы можете добавить крюк отключения для сообщения "Это закончено". Таким образом, он будет создан, когда программа завершится, и вам не нужно ждать каждого потока.

Вы можете использовать метод соединения. Обратитесь к документации здесь

У вас есть лучшие варианты, если вы идете для ExecutorService или ThreadPoolExecutor Framework.

  1. invokeAll

    Выполняет заданные задачи, возвращая список Фьючерсов с их статусом и результатами, когда все выполнено. Future.isDone() имеет значение true для каждого элемента возвращаемого списка. Обратите внимание, что завершенная задача могла быть завершена либо нормально, либо с помощью исключения. Результаты этого метода не определены, если данная коллекция была изменена во время выполнения этой операции. Параметры типа:

  2. CountDownLatch: инициализировать CountDownLatch со счетчиком как количество потоков. использование countDown() а также await() API и ждать, пока счетчик станет нулевым.

Дальнейшие ссылки:

Как использовать invokeAll(), чтобы все пулы потоков выполняли свою задачу?

Как CountDownLatch используется в многопоточности Java?

Попробуйте этот пример:

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
        }
    }
}

Вы могли бы сделать последнюю строку в потоке "мониторинга". Он будет проверять так часто, что это единственный запущенный поток и состояние завершения == true а затем мог выстрелить, если бы это было. Тогда это может сделать другие вещи, чем просто println

Самый простой способ

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

Я знаю, что блокировать основной поток... но он работает отлично!

Другие вопросы по тегам