Подтвердить что ты не робот

Как приостановить 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!");

}

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

Эрик

4b9b3361

Ответ 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

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

  • CountDownLatch: Инициализировать CountDownLatch с помощью счетчика в виде количества потоков. Используйте API-интерфейсы countDown() и await() и подождите, пока счетчик не станет равным нулю.

Другие ссылки:

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

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