Thread как остановить поток java

Аватар пользователя Игорь Черкасов
Игорь Черкасов
29 декабря 2022

Принудительно останавливать поток крайне не рекомендуется. Соответствующий метод был признан "нежелательным" к использованию (Документация 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-ю) и завершится.

0 0

Есть что добавить? Зарегистрируйтесь

или войдите в аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Курсы по программированию в Хекслете

Программирование

Веб-разработка

Разработка, верстка и деплой сайтов и веб-приложений, трудоустройство для разработчиков

Frontend-разработка

Разработка внешнего интерфейса сайтов и веб-приложений и верстка

Создание сайтов

Разработка сайтов и веб-приложений на JS, Python, Java, PHP и Ruby on Rails

Backend-разработка

Разработка серверной части сайтов и веб-приложений

Тестирование

Ручное тестирование и автоматизированное тестирование на JS, Python, Java и PHP

Аналитика данных

Сбор, анализ и интерпретация данных на Python

Интенсивные курсы

Интенсивное обучение для продолжающих

DevOps

Автоматизация настройки локального окружения и серверов, развертывания и деплоя

Математика для программистов

Обучение разделам математики, которые будут полезны при изучении программирования

Тест-драйв

JavaScript

Разработка сайтов и веб-приложений и автоматизированное тестирование на JS

Python

Веб-разработка, автоматическое тестирование и аналитика данных на Python

Java

Веб-разработка и автоматическое тестирование на Java

PHP

Веб-разработка и автоматическое тестирование на PHP

Ruby

Разработка сайтов и веб-приложений на Ruby on Rails

Go

Курсы по веб-разработке на языке Go

HTML

Современная верстка с помощью HTML и CSS

SQL

Проектирование базы данных, выполнение SQL-запросов и изучение реляционных СУБД

Git

Система управления версиями Git, регулярные выражения и основы командой строки

Бесплатные курсы

Бесплатные курсы по тестированию, дата-аналитике, верстке, программированию на Python, Java, PHP и JavaScript.