Как остановить поток?
В Java поток представлен классом Thread . В нём есть метод stop() , но пользоваться им нельзя, метод помечен как deprecated. Такая жесткая остановка моментально возвращает все захваченные потоком мониторы, и защищенные ими данные могут оказаться в неконсистентном состоянии.
Разработчики рекомендуют вместо этого использовать флаг, который будет показывать о намерении остановить поток. Флаг выставляется извне потока, а внутри проверяется в подходящий момент. Если нужно остановиться, поток просто выходит из метода run() . В качестве такого флага подойдет переменная типа AtomicBoolean .
Когда в потоке используются блокирующие операции, обычно для определенного типа операции существует свой способ её прервать. Например, можно закрыть сокет, на котором поток ожидает. Для большинства блокирующих операций сработает метод Thread.interrupt() . С его помощью можно прервать Object.wait() и операции из NIO.
Останется только правильно обработать такое прерывание. Прерванный wait() выбросит InterruptedException , Selector.select() вернет результат. Чтобы отличить осознанное прерывание с целью завершить тред от какого-либо другого, его обработку всё ещё необходимо снабдить проверкой флага.
Как удалить или остановить поток?
Как удалить или остановить поток, чтобы выполнить определенное действие и запустить (желательно удалить)?
Отслеживать
25.1k 4 4 золотых знака 45 45 серебряных знаков 81 81 бронзовый знак
задан 17 ноя 2015 в 19:56
157 1 1 золотой знак 2 2 серебряных знака 8 8 бронзовых знаков
создайте функцию завершения потока на самом классе потока (destructor)
17 ноя 2015 в 19:58
@Saidolim так себе совет. Поток не должен заниматься менеджментом себя.
17 ноя 2015 в 19:59
Почитайте эту статью. Вкратце, ваш поток должен проверять «а не прерван ли я?» и если «прерван» — завершить свою работу сам, так как он умеет. Освободив ресурсы, откатив транзакции и прочее.
17 ноя 2015 в 20:13
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Все потоки нужно прерывать при помощи метода interrupt() .
В самом потоке, который возможно будет прерван — нужно устанавливать проверки isInterrupted() во всех ключевых точках (где это необходимо) и обрабатывать соответственно.
Ну это если в двух словах, а так лучше прочтите что-то по типу этой статьи на Хабре.
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Main < public static void main(String[] args) < final HelloThread helloThread = new HelloThread(); //final - для таймера helloThread.start(); Timer timer = new Timer(1000, new ActionListener() < @Override public void actionPerformed(ActionEvent event) < System.out.println("Interrupting thread. "); helloThread.interrupt(); >>); timer.setRepeats(false); timer.start(); System.out.println("Thread main still work"); > > class HelloThread extends Thread < public void run() < try < for (int i = 0; i < 1000000; i++) < if (!isInterrupted())/isInterrupted проверять в любых ключевых точках, // где можно обработать прерывание потока if(i%5==1) System.out.println("Hello from a thread! " + i); > else < throw new InterruptedException(); //бросаем исключение в таких случаях как этот (циклы) >> > catch (InterruptedException e) < System.out.println("Thread is interrupted"); //Закрываем все стримы если есть >//Не забывайте, что поток завершается когда нечего испонять System.out.println("Nothing to say"); //и окончательно он завершится после этой строки > >
Вообще в java doc не рекомендуют пользоваться deprecated методами (такими как Thread.stop() ). Метод Thread.stop() убивает поток не обрабатывая и самое главное —
поток может быть «убит» во время выполнения операции, обрыв которой на полуслове оставит некоторый объект в неправильном состоянии, что приведет к появлению трудноотлавливаемой и случайным образом возникающей ошибке
(цитата из все той-же статьи на Хабре)
StanislavShestakov / com.javarush.test.level16.lesson10.task03.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| package com . javarush . test . level16 . lesson10 . task03 ; |
| /* Снова interrupt |
| Создай нить TestThread. |
| В методе main создай экземпляр нити, запусти, а потом прерви ее используя метод interrupt(). |
| */ |
| public class Solution |
| public static void main ( String [] args ) throws InterruptedException |
| //Add your code here — добавь код тут |
| TestThread tread = new TestThread (); |
| > |
| //Add your code below — добавь код ниже |
| public static class TestThread extends Thread |
| public void run () |
| currentThread (). interrupt (); |
| > |
| > |
| > |
Java. Остановись задача
Вот уже почти год как усиленно занимаюсь коддингом на Java. Столкнулся с довольно серьезной на мой взгляд проблемой, связанных с многопоточностью, как мне кажется, неразрешимой в рамках текущей реализации JVM от Oracle (сказанное относится к JDK 1.5 и выше). Дело в том, что на данный момент в Java нет возможности гарантированно безопасно остановить выполнение какого-либо потока. Данный пост разъясняет почему это именно так и предлагает начать дискуссию о способах решения этой проблемы.
Казалось бы тривиальная задача: имеем некий Thread (поток), который, мы точно знаем, безнадежно завис (может зациклился, может, что-то еще), при этом потребляет некоторые ресурсы. Что нам с ним делать? Хотелось бы ресурсы наши освободить. Казалось бы, что проще? Ан нет, при детальном изучении вопроса оказалось, что в JVM просто нет инструкции, чтобы корректно остановить зависший Thread. Старый метод Thread.stop() объявлен Deprecated и предан строжайшей анафеме. Как сказано в javadoc’е это метод «по сути небезопасен». Ну что же, если не безопасен не будем его использовать, дайте нам другой, безопасный метод. Но другого безопасного как ни странно не предлагается. Предлагается, безусловно, очень безопасная инструкция Thread.interrupt(). Но безопасна она, к сожалению, потому, что ровным счетом ничего не делает! Это всего лишь сообщение потоку: «Пожалуйста, остановись». Но если поток данное сообщение проигнорировал то… как сказано в документации «Если поток не отвечает на Thread.interrupt() вы можете использовать специфические для вашего приложению трюки». Спасибо, что разрешили. Что называется, крутись как хочешь.
Все становится еще сложней, если задача запущена в пуле потоков, через, например, ExecutorService.submit(Runnable). При этом мы даже не знаем, в каком именно потоке данная задача выполняется и уже не может применить даже запрещенный Thread.stop(). С другой стороны, мы имеем ссылку на Future, а у Future есть метод Future.cancel(boolean), который должен отменить выполнение задачи. Но если задача уже начала выполняться, вызов Future.cancel(true) на самом деле не остановит ее. В недрах реализации FutureTask выполняется код:
if (mayInterruptIfRunning) Thread r = runner;
if (r != null)
r.interrupt(); >
Т.е. опять потоку, в котором выполняется задача, всего лишь рекомендуется прекратить выполнение. К тому же, мы не имеем даже возможности узнать выполняется ли задача в данный момент или нет. Есть, вроде, метод Future.isDone(), но опять мимо, он возвращает true не только когда задача завершила выполнение, а сразу после вызова Future.cancel(), даже если задача все еще выполняется (ведь Future.cancel(true) не останавливает задачу которая уже начала выполняться).
Хорошо, если мы сами пишем весь код, тогда можно в нужных местах аккуратно обрабатывать Thread.isInterrupted() и все будет ОК. Но если мы запускаем сторонний код? Если у нас есть сервер расширяемый с помощью плагинов? Какой-нибудь криво написанный плагин может запросто привести к неработоспособному состоянию весь сервер ведь мы не можем корректно прервать выполнение зависшего плагина.
Признаюсь, я не знаю удовлетворительного решения. Может быть, метод Thread.stop() не так уж опасен? Очень хотелось бы услышать мнения Java программистов практиков по этому поводу.
