Использование isAlive() и join()

Как упоминалось, часто необходимо, чтобы главный поток завершался последним. В предыдущих примерах это обеспечивается вызовом sleep () из main () с задержкой, достаточной для того, чтобы гарантировать, что все дочерние потоки завершатся раньше главного. Однако это неудовлетворительное решение, которое вызывает серьезный вопрос: как один поток может знать о том, что другой завершился? К счастью, Thread предлагает средство, которое дает ответ на этот вопрос.

Существуют два способа определить, что поток был завершен. Во-первых, вы можете вызвать метод isAlive () для этого потока. Этот метод определен в классе Thread и его общая форма такова:

final Boolean isAlive()

Метод isAlive () возвращает true, если поток, для которого он вызван, еще выполняется. В противном случае он возвращает false.

В то время как isAlive () применяется изредка, существует метод, который вы будете использовать чаще, чтобы дождаться завершения потока, а именно — join (), показанный ниже:

final void join() throws InetrruptedException

Этот метод ожидает завершения потока, для которого он вызван. Его имя отражает концепцию, что вызывающий поток ожидает, когда указанный поток присоединиться к нему. Дополнительные формы join () позволяют указывать максимальный период времени, которое вы будете ожидать завершения указанного потока.

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

// Применение 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() {
try {
for(int i = 5; i > 0; i—) {
System.out.println(name + ": " + i) ;
Thread.sleep(1000);
}
}
catch (InterruptedException e) {
System.out.println(name + " прерван.");
}
System.out.println(name + " завершен.");
}
}
class DemoJoin {
public static void main(String args[]) {
NewThread obi = new NewThread("Одни");
NewThread ob2 = new NewThread("Два");
NewThread ob3 = new NewThread("Три");
System.out.println("Поток Один запущен: " + obl.t.isAlive());
System.out.println("Поток Два запущен: " + ob2.t.isAlive());
System.out.println("Поток Три запущен: " + ob3.t.isAlive());
// ожидать завершения потоков
try {
System.out.println("Ожидание завершения потоков.");
obi.t.join () ;
ob2.t.join () ;
ob3.t.join();
}
catch (InterruptedException e) {
System.out.println("Главный поток прерван");
}
System.out.println("Поток Один запущен: " + obl.t.isAlive());
System.out.println("Поток Два запущен: " + ob2.t.isAlive());
System.out.println("Поток Три запущен: " + ob3.t.isAlive());
System.out.println("Главный поток завершен.");
}
}

Пример вывода этой программы показан ниже (ваш вывод может отличаться в зависимости от скорости и загрузки процессора).

Новый поток: Thread[Один,5,main]
Новый поток: Thread[Два,5,main]
Новый поток: Thread[Три,5,main]
Поток Один запущен: true
Поток Два запущен: true
Поток Три запущен: true
Ожидание завершения потоков.
Один: 5
Два: 5
Три: 5
Один: 4
Два: 4
Три: 4
Один: 3
Два: 3
Три: 3
Один: 2
Два: 2
Три: 2
Один: 1
Два: 1
Три: 1
Два завершен.
Три завершен.
Один завершен.
Поток Один запущен: false
Поток Два запущен: false
Поток Три запущен: false
Главный поток завершен.

Как видите, после того как вызовы join () вернут управление, потоки прекращают работу.