Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > метод join


Автор: Pawl 8.3.2011, 23:48
Уважаемые господа,
В http://topcode.ru/2010/04/14/potoki-v-java-chast-2/ вычитал, что метод join(), вызванный на потоке t, "блокирует текущий поток до того времени пока поток t не умрет". Когда 2 потока понятно, а как работает этот метод если в приложении запущено 3 и более потоков? Если на одном из них вызвать join, как понять, какой из остальных будет заблокирован? В одной книге нашел пример и немного его переделал:
Код

class NewThread implements Runnable {
    String name; // имя потока
    Thread t;
    
    NewThread(String threadname) {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("Новый поток: " + t);
        t.start();
    }
    
    public void run() {
        for (int i = 3; i > 0; i--) {
            System.out.println(name + ": " + i);
        }            
        System.out.println(name + " завершен.");
    }
}

Код

class DemoJoin {
    public static void main(String args[]) {
        try {
            NewThread ob1 = new NewThread("Первый");
            ob1.t.join();
            NewThread ob2 = new NewThread("Второй");
            ob2.t.join();
            NewThread ob3 = new NewThread("Третий");
            ob3.t.join();            
        } catch (InterruptedException e) {}
        System.out.println("Завершение главного потока.");
    }
}

вывод тут получается нормальный:
Новый поток: Thread[Первый,5,main]
Первый: 3
Первый: 2
Первый: 1
Первый завершен.
Новый поток: Thread[Второй,5,main]
Второй: 3
Второй: 2
Второй: 1
Второй завершен.
Новый поток: Thread[Третий,5,main]
Третий: 3
Третий: 2
Третий: 1
Третий завершен.
Завершение главного потока.

Но если класс DemoJoin сделать так:
Код

class DemoJoin {
    public static void main(String args[]) {
        try {
            NewThread ob1 = new NewThread("Первый");
            NewThread ob2 = new NewThread("Второй");
            NewThread ob3 = new NewThread("Третий");
            ob3.t.join();            
        } catch (InterruptedException e) {}
        System.out.println("Завершение главного потока.");
    }
}

получается, что поток ob3 завершается предпоследним, перед завершением главного потока. Потоки ob1 и ob2 не присоединяются к ob3 (не блокируются), а заканчиваются раньше него. Вот и прошу я объяснить мне тонкости работы с методом join!
Большое спасибо заранее!

Автор: jk1 9.3.2011, 04:01
Цитата

Если на одном из них вызвать join, как понять, какой из остальных будет заблокирован?


Текущий будет заблокирован, из которого вызывали. Все же написано:

Цитата

метод join(), вызванный на потоке t, блокирует текущий поток до того времени пока поток t не умрет


Текуший поток будет заблокирован до завершения потока t. Все остальные потоки будут работать как и раньше, сколько бы их не было.

Цитата

Потоки ob1 и ob2 не присоединяются к ob3 (не блокируются), а заканчиваются раньше него.


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

Так что результат вполне предсказуем.

Автор: Pawl 9.3.2011, 09:07
Цитата

Текуший поток будет заблокирован до завершения потока t

Спасибо за ответ, но все же прошу уточнить. Если в приложении работают несколько потоков, они же все будут текущими? Так как же понять, какой из этих самых "текущих потоков" будет заблокирован?
Цитата

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

Вообще-то, по-моему, тут запускается 4 потока: основной, ob1, ob2 и ob3 причем именно в такой последовательности. Так вот, в примере дожидается завершения ob3 всегда только основной поток. Честно, непонятно, почему в данном случае "текущим" считается основной поток, а ob1 или ob2 - нет?

Автор: jk1 9.3.2011, 11:09
Цитата

Спасибо за ответ, но все же прошу уточнить. Если в приложении работают несколько потоков, они же все будут текущими?

Нет. Текуший поток - это поток выполняющий вызов join(). Кто этот вызов выполнил, тот и будет ждать окончания целевого потока. Посмотрите внимательно на Ваш класс NewThread. Он вызывает join()? Нет, значит и ждать он никого не будет. А вот starter thread, который исполняет main метод, делакт такой вызов, потому и ждет завершения.

Автор: Pawl 9.3.2011, 11:19
Спасибо огромное, помогли разобраться!
Закрываю тему.

Добавлено через 47 секунд
ВОПРОС РЕШЁН!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)