/
Вопросы и ответы
/
Java
/

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

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

5 лет назад

Человек-Молекула

Ответы

0

Принудительно останавливать поток крайне не рекомендуется. Соответствующий метод был признан "нежелательным" к использованию (Документация Oracle). Проблема в том, что поток может быть остановлен в процессе выполнения операции и приведет к ошибке, которую сложно будет выявить и исправить. Кроме того, внезапная остановка может привести к потере данных.

Вместо принудительной остановки потока необходимо использовать метод оповещения о прекращении работы потока - interrupt(). Данный метод установит флаг прерывания потока (прекращения работы), который можно проверить методом isInterrupted() и указать логику его обработки и завершения работы потока.

Если же поток был заблокирован, находился в ожидании (wait, sleep, join), то будет сброшен флаг прерывания и выброшено исключение InterruptedException. В таком случае, после обработки исключения и для прерывания потока, необходимо заново установить флаг прерывания методом interrupt().

Пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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-ю) и завершится.

3 года назад

Игорь Черкасов

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845