Почему я не могу запустить операторы в main () после того, как мои потоки перестают работать? - PullRequest
0 голосов
/ 05 января 2019

Итак, у меня есть программа с 4-мя потоками, все они работают. 3 из этих потоков всегда работают, даже когда программа заканчивает свою работу. Поэтому я создал несколько переменных, чтобы они прекратились.

Я изменил while(true) на while(exit) и программа работает нормально.

После потоков я хочу выполнить некоторые другие операторы, но только если потоки остановились.

Я попытался использовать 4 переменные, выход, выход1, выход2, выход3 и установить их в ложь. Поток завершится и сделает эти переменные истинными.

В основном, после Thread.start(), если я хочу что-то напечатать, оно не печатается.

Thread1.start();
Thread2.start();
Thread3.start();
Thread4.start();

// System.out.println("Program Ended") --> If i do this, it prints before 
// the threads

if(exit && exit2 && exit3 && exit4) {
    System.out.println("Program Ended");
    // code here 
}

Есть ли способ убедиться, что некоторые операторы выполняются только после остановки потоков?

Ответы [ 4 ]

0 голосов
/ 05 января 2019

Использование ThreadGroup для управления несколькими потоками может быть более элегантным и удобным при большом количестве потоков.

Код образца:

ThreadGroup tg = new ThreadGroup("runner");

new Thread(tg, () -> {
    // ...
}, "t-1").start();

new Thread(tg, () -> {
    // ...
}, "t-2").start();

// create more  threads,

Thread[] tArr = new Thread[tg.activeCount()];
cg.enumerate(tArr); // get threads,

// wait all consumers to finish,
for (Thread t : tArr) {
    t.join();
}

Советы:

  • При создании нового потока укажите группу потоков в конструкторе.
  • После запуска всех подпотоков, получить потоки из группы потоков и присоединиться к каждому из них.

Кстати:

  • ThreadGroup.activeCount() будет возвращать только те потоки, которые еще не завершены.
0 голосов
/ 05 января 2019

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

thread1.start();
thread2.start();
thread3.start();
thread4.start();

thread1.join();
thread2.join();
thread3.join();
thread4.join();

if (exit && exit2 && exit3 && exit4) {
    System.out.println("Program Ended");
}

Это обеспечит выполнение блока if только после смерти каждого из потоков.

0 голосов
/ 05 января 2019

В качестве альтернативы вы должны рассмотреть CyclicBarrier или CountDownLatch.
Они менее подвержены ошибкам, обычно менее многословны и довольно эффективны по сравнению с пользовательскими флагами завершающих потоков.

Есть свои особенности, но они довольно близки. CountDownLatch связывает счетчик операций countDown для достижения, в то время как CyclicBarrier связывает счетчик отдельного потока, вызывающего await() для применения определенной обработки.

С CyclicBarrier это может выглядеть так:

CyclicBarrier barrier = new CyclicBarrier(4, () -> {
        System.out.println("Program Ended");
});

Здесь 4 - это номер потока, который должен ждать на барьере, и «Программа завершена» будет отображаться, когда 4 отдельных потока «достигнут» барьера.

Нить может достичь барьера после их обработки, например:

new Thread(() -> {
    while (!done()) {
        ....
    }
    barrier.await();  // replace the flag boolean
});

Обратите внимание, что барьер является циклическим. Это означает, что его можно использовать повторно после активации. В отличие от CountDownLatch.

0 голосов
/ 05 января 2019

В классе Thread есть метод, который делает это для вас join будет блокироваться, пока поток не завершит выполнение. Baeldung учебник, как использовать Thread#join

Итак, ваш код должен выглядеть так:

thread1.start();
thread2.start();
thread3.start();
thread4.start();

thread1.join();
thread2.join();
thread3.join();
thread4.join();

if(exit && exit2 && exit3 && exit4) {
    System.out.println("Program Ended");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...