Перейти к основному содержимому

Как убить поток Java

· 3 мин. чтения

1. Введение

В этой краткой статье мы рассмотрим остановку потока в Java, что не так просто, поскольку метод Thread.stop() устарел.

Как объясняется в этом обновлении от Oracle, stop() может привести к повреждению отслеживаемых объектов.

2. Использование флага

Начнем с класса, который создает и запускает поток. Эта задача не завершится сама по себе, поэтому нам нужен способ остановить этот поток.

Для этого мы будем использовать атомарный флаг:

public class ControlSubThread implements Runnable {

private Thread worker;
private final AtomicBoolean running = new AtomicBoolean(false);
private int interval;

public ControlSubThread(int sleepInterval) {
interval = sleepInterval;
}

public void start() {
worker = new Thread(this);
worker.start();
}

public void stop() {
running.set(false);
}

public void run() {
running.set(true);
while (running.get()) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
System.out.println(
"Thread was interrupted, Failed to complete operation");
}
// do something here
}
}
}

Вместо цикла while , оценивающего константу true , мы используем AtomicBoolean , и теперь мы можем запускать/останавливать выполнение, устанавливая его в true/false.

Как объяснялось во введении к атомарным переменным , использование AtomicBoolean предотвращает конфликты при установке и проверке переменной из разных потоков.

3. Прерывание потока

Что происходит, когда для sleep() установлен большой интервал или если мы ждем блокировку , которая может никогда не быть снята?

Мы сталкиваемся с риском блокировки на длительный период или никогда не завершаем чисто.

Мы можем создать прерывание() для таких ситуаций, давайте добавим в класс несколько методов и новый флаг:

public class ControlSubThread implements Runnable {

private Thread worker;
private AtomicBoolean running = new AtomicBoolean(false);
private int interval;

// ...

public void interrupt() {
running.set(false);
worker.interrupt();
}

boolean isRunning() {
return running.get();
}

boolean isStopped() {
return stopped.get();
}

public void run() {
running.set(true);
stopped.set(false);
while (running.get()) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
System.out.println(
"Thread was interrupted, Failed to complete operation");
}
// do something
}
stopped.set(true);
}
}

Мы добавили метод interrupt() , который устанавливает флаг выполнения в false и вызывает метод interrupt() рабочего потока .

Если поток спит, когда это вызывается, sleep() завершится с InterruptedException, как и любой другой блокирующий вызов.

Это возвращает поток в цикл, и он завершится, так как выполнение ложно.

4. Вывод

В этом кратком руководстве мы рассмотрели, как использовать атомарную переменную, при необходимости в сочетании с вызовом interrupt(), для корректного закрытия потока. Это определенно предпочтительнее вызова устаревшего метода stop() и риска вечной блокировки и повреждения памяти.

Как всегда, полный исходный код доступен на GitHub .