В Java нет официального метода завершения потока. Остановка потока полностью управляется JVM. Хотя Java предоставляет несколько способов управления жизненным циклом потока, таких как start(), sleep(), stop()( устарело в Java 1.1 ) и т. д., но не предоставляет ни одного метода завершения потока и чистого освобождения ресурсов.
Oracle указала причину прекращения поддержки метода stop(), так как он изначально небезопасен. Остановка потока приводит к разблокировке всех заблокированных им мониторов.
1. Два способа закрыть тему
Фактически, мы можем только подать сигнал потоку, чтобы он остановил себя и позволил потоку очистить ресурсы и завершить себя. В Java мы можем послать сигнал потоку двумя способами:
- Периодически проверяя логический флаг
- Прерывая поток с помощью метода Thread.interrupt()
Давайте узнаем больше об обоих методах:
2. Проверяя флаг
В этом методе мы периодически проверяем логический флаг или после каждого шага в задаче. Изначально флаг установлен на false. Чтобы остановить поток, установите флаг на true. Внутри потока, когда код проверяет значение флага на true, он изящно уничтожает себя и возвращается.
Обратите внимание, что в этой конструкции, как правило, есть два потока. Один поток устанавливает значение флага в true, а другой поток проверяет значение флага. Чтобы гарантировать, что оба потока все время видят одно и то же значение, мы должны сделать переменную флага volatile. Или мы можем использовать класс AtomicBoolean, который поддерживает атомарные операции с базовой переменной volatile boolean.
открытый класс CustomTask реализует Runnable {частный изменчивый логический флаг = false;частный рабочий поток;public void start() {работник = новый поток(этот);работник.старт();}публичная недействительная остановка() {флаг = истина;}@Переопределитьpublic void run() {в то время как(!флаг) {пытаться {Поток.сон(500);System.out.println(Thread.currentThread().getName() + " Выполняется...");} поймать(InterruptedException e) {Поток.текущийПоток().прерывание();System.out.println("Поток был прерван," + e.getMessage());}}System.out.println(Thread.currentThread().getName() + " Остановлен");возвращаться;}}
Давайте проверим эту конструкцию, создав два потока и остановив их.
CustomTask task1 = new CustomTask();CustomTask task2 = new CustomTask();task1.start();task2.start();try {Thread.sleep(1000);task1.stop();task2.stop();} catch(InterruptedException e) {System.out.println("Caught:" + e);}
Тема-0 Работает...Тема-1 Работает...Тема-1 Работает...Тема-0 Работает...Тема-1 остановленаТема-0 остановлена
3. Прерывая нить
Этот метод также очень похож на предыдущий подход с использованием флага. Единственное отличие в том, что мы прерываем поток вместо того, чтобы устанавливать флаг в false.
Итак, внутри потока мы будем продолжать проверять статус прерывания потока, и когда поток прерывается, мы остановим поток изящно. Чтобы проверить статус прерванного потока, мы можем использовать метод Thread.isInterrupted(). Он возвращает true или false в зависимости от статуса прерывания потока.
открытый класс CustomTaskV2 реализует Runnable {частный рабочий поток;public void start() {работник = новый поток(этот);работник.старт();}public void прерывание() {работник.прерывание();}@Переопределитьpublic void run() {пока(!Thread.currentThread().isInterrupted()) {пытаться {Поток.сон(500);System.out.println(Thread.currentThread().getName() + " Выполняется...");} поймать(InterruptedException e) {Поток.текущийПоток().прерывание();System.out.println("Поток был прерван по причине: " + e.getMessage());}}System.out.println(Thread.currentThread().getName() + " Остановлен");возвращаться;}}
Интересно, что код для проверки этой конструкции похож на предыдущий. Дополнительным является только вызов метода thread.interrupt().
CustomTaskV2 task1 = new CustomTaskV2();CustomTaskV2 task2 = new CustomTaskV2();task1.start();task2.start();try {Thread.sleep(1100);isInterruptedtask1.interrupt();task2.interrupt();} catch(InterruptedException e) {System.out.println("Caught:" + e);}
Тема-0 Работает...Тема-1 Работает...Тема-1 Работает...Тема-0 Работает...Тема была прервана по причине: прерван сонТема была прервана по причине: прерван сонТема-0 остановленаТема-1 остановлена
4. Заключение
Этот урок научил нас убивать работающий поток в Java с помощью пользовательских решений. Несмотря на то, что решение с использованием булевых флагов очень хорошее, оно может не дать желаемого результата для длительных задач, где поток большую часть времени находится в состоянии ожидания.
Отправка прерывания — гораздо лучший способ остановить долго ожидающий поток.