Ожидание завершения потока sh с .join incosistent - PullRequest
1 голос
/ 17 июня 2020

Рассмотрим этот код:

    public class print extends Thread {

public void run() {
    Out.print("Hello");
    Out.println("World");
}
}

public class test {
public static void main (String[] args) {
    Thread t1 = new print();
    Thread t2 = new print();
    Thread t3 = new print();
    Thread t4 = new print();
    Thread t5 = new print();

    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();

    try {
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        t5.join();
    }catch(InterruptedException e) {
    }
}

}

Цель состоит в том, чтобы напечатать hello, чем world в следующей строке. Вывод неверный и очень противоречивый , то есть каждые несколько тестов он меняется. Я никогда не работал с потоками, но я провел некоторое исследование, и в нем говорится, что при использовании этого .join следует дождаться, пока один поток завершит sh, чтобы запустился следующий. Что я делаю не так?

Спасибо!

1 Ответ

2 голосов
/ 17 июня 2020

, и в нем говорится, что использование этого .join должно ждать, пока один поток завершит sh, так что следующий запускается

Это не то, что делает join.

join блокирует текущий поток до тех пор, пока целевой поток не будет завершен. Он ничего не делает с другими потоками.

В вашем случае основной поток будет ждать от t1 до fini sh, затем до t2 и так далее. Но он ничего не делает для планирования работы t1 по отношению к t2. В частности, он также не задерживает запуск t2. t2 начинается, когда вы сказали t2.start().

Хорошо, как мне сказать остальным подождать?

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

Если вы действительно хотите продолжить это, посмотрите на ReentrantLock или CountDownLatch. Или используйте t1, позвоните t2.join().

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

Также обратите внимание, что если вы хотите запускать эти задачи последовательно одну за другой, вам вообще не нужно несколько потоков. Просто введите t1.run(); t2.run(); t3.run(); в том же потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...