Современный способ приостановки, возобновления и остановки потоков

Хотя применение методов класса Thread по именам suspend (), resume () и stop () выглядит как исключительно разумный и удобный подход к управлению выполнением потоков, они не должны использоваться в новых Java-программах. И вот почему. Метод suspend () класса Thread несколько лет назад был объявлен нежелательным в Java 2. Это было сделано потому, что иногда он способен порождать серьезные системные сбои. Предположим, что поток пытается получить блокировки на критичных структурах данных. Если поток приостановит в этот момент, блокировки не будут установлены. Другие потоки, которые могут ожидать этих ресурсов, могут оказаться взаимно заблокированными.

Метод resume () также нежелателен. Он не вызовет проблем, но не может быть использован без метода suspend () как своего дополнения.

Метод stop () класса Thread также объявлен устаревшим в Java 2. Это было сделано потому, что он также иногда может послужить причиной серьезных системных сбоев. Предположим, что поток выполняет запись в критически важную структуру данных, и успел выполнить только частичное обновление. Если его остановить в этот момент, структура данных может оказаться в поврежденном состоянии.

Поскольку вы не можете теперь использовать методы suspend(), resume() или stop () для управления потоками, то можете подумать, что теперь вообще нет способа приостановить, возобновить или прервать поток. К счастью, это не так. Вместо этого поток должен быть проектирован так, чтобы метод run () периодически проверял, должно ли выполнение потока быть приостановлено, возобновлено или прервано. Обычно это достигается использованием переменной-флага, указывающей состояние потока. До тех пор, пока этот флаг имеет значение "запущен", метод run () должен продолжать выполнение. Если переменная имеет значение "прерван", поток должен приостановиться. Если флаг получает значение "стоп", то поток должен завершиться. Конечно, существует множество способов написать такой код, но основной принцип остается неизменным для всех программ.

В следующем примере показано как методы wait () и notify (), унаследованные от Ob j ect, могут применяться для управления выполнением потока. Этот пример похож на программу из предыдущего раздела. Однако вызовы устаревших методов в ней исключены. Рассмотрим работу этой программы.

Класс NewThread содержит переменную экземпляра типа boolean по имени suspendFlag, используемую для управления выполнением потока. Конструктор инициализирует ее значением false. Метод run () содержит блок synchronized, который проверяет состояние suspendFlag. Если ее значение равно true, вызывается метод wait () для приостановки выполнения потока. Метод mysuspend () устанавливает значение suspendFlag в true. Метод myresime () устанавливает suspendFlag в false и вызывает notify () для того, чтобы "разбудить" поток. И, наконец, метод main () модифицирован для вызова методов mysuspend () и myresime ().

// Приостановка и возобновление потока современным способом.
class NewThread implements Runnable {
String name; // имя потока
Thread t;
boolean suspendFlag;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("Новый поток: " + t) ;
suspendFlag = false;
t.startO;
// запустить поток
}
// Точка входа потока.
public void run() {
try {
for(int i = 15; i > 0; i—) {
System.out.println(name + ": " + i);
Thread.sleep(200);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
}
catch (InterruptedException e) {
System.out.println(name + " прерван.");
}
System.out.println(name + " завершен.");
}
void mysuspend() {
suspendFlag = true;
}
synchronized void myresumeO {
suspendFlag = false;
notify();
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread obi = new NewThread("Один");
NewThread ob2 = new NewThread("Два");
try {
Thread.sleep (1000);
obi.mysuspend();
System.out.println("Приостановка потока Один");
Thread.sleep(1000);
obi.myresume () ;
System.out.println("Возобновление потока Один");
ob2.mysuspend();
System.out.println("Приостановка потока Два");
Thread.sleep(lOOO);v ob2.myresume();
System.out.println("Возобновление потока Два");
}
catch (InterruptedException e) {
System.out.println("Главный поток прерван");
// ожидание завершения потоков try {
System.out.println("Ожидание завершения потоков.");
obi.t.join ();
ob2.t.join();
}
catch {
InterruptedException e) {
System.out.println("Главный поток прерван");
}
System.out.println("Главный поток завершен");
}
}

Вывод этой программы идентичен приведенному в предыдущем разделе. Чуть позднее в этой книге вы найдете еще примеры, в которых используется современный механизм управления потоками. Хотя этот метод не так "чист", как старый, его следует придерживаться, дабы избежать ошибок времени выполнения. Это подход, который должен применяться во всем новом коде.




Rambler's Top100