Thread как остановить поток java
Принудительно останавливать поток крайне не рекомендуется. Соответствующий метод был признан "нежелательным" к использованию (Документация Oracle). Проблема в том, что поток может быть остановлен в процессе выполнения операции и приведет к ошибке, которую сложно будет выявить и исправить. Кроме того, внезапная остановка может привести к потере данных.
Вместо принудительной остановки потока необходимо использовать метод оповещения о прекращении работы потока - interrupt()
. Данный метод установит флаг прерывания потока (прекращения работы), который можно проверить методом isInterrupted()
и указать логику его обработки и завершения работы потока.
Если же поток был заблокирован, находился в ожидании (wait, sleep, join), то будет сброшен флаг прерывания и выброшено исключение InterruptedException
. В таком случае, после обработки исключения и для прерывания потока, необходимо заново установить флаг прерывания методом interrupt()
.
Пример:
import java.util.ArrayList;
public class ThreadInterruptClass {
public static void main(String[] args) {
//создаем пул задач для выполнения
TasksPool tasksPool = new TasksPool();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//проверяем флаг завершения работы потока
while(!Thread.currentThread().isInterrupted()) {
Runnable task = null;
try {
task = tasksPool.get();
task.run();
} catch (InterruptedException e) {
//т.к. исключением был сброшен флаг завершения работы потока,
//устанавливаем его снова
Thread.currentThread().interrupt();
}
}
}
});
thread.start();
//генерируем задачи в пул задач
for (int i = 0; i < 5; i++) {
tasksPool.put(taskGenerator());
}
//Оповещаем о завершении работы потока, после 3 секунд выполнения.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Если не прервать выполнение потока, работа программы не завершится.
thread.interrupt();
}
//Метод для генерирования задач.
//Выводит сообщение о старте выполнения задачи, ожидает 1 секунду
//и выводит сообщение о завершении задачи.
public static Runnable taskGenerator() {
return new Runnable() {
@Override
public void run() {
System.out.println("Task started: " + this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//т.к. исключением был сброшен флаг завершения работы потока,
//устанавливаем его снова
Thread.currentThread().interrupt();
}
System.out.println("Task finished: " + this);
}
};
}
//Класс для хранения пула задач, который выдает задачу, если она есть,
//если задачи нет - блокирует выполнения потока, и принимает задачу,
//одновременно снимая блокировку с потока
static class TasksPool {
ArrayList<Runnable> tasks = new ArrayList<>();
//метод, который выдает из пула задачу
//если задачи нет, блокируем поток
public synchronized Runnable get() throws InterruptedException {
while (tasks.isEmpty()) {
wait(); //блокируем выполнение потока
}
Runnable task = tasks.get(0);
tasks.remove(task);
return task;
}
//метод для помещения задачи в пул
//и снятия блокировки с потока
public synchronized void put(Runnable task) {
tasks.add(task);
notify(); //снимаем блокировку с потока
}
}
}
При запуске данного кода будет выполнено 3 задачи, хотя в цикле сгенерируется 5 задач. Все потому, что метод interrupt()
будет вызван с 3-х секундной задержкой, поток выполнит текущую задачу (в данном случае 3-ю) и завершится.