Как правильно остановить поток в Java/Kotlin и какие методы существуют
Что проверяют
Знаете ли вы, что поток нельзя остановить снаружи принудительно, можно только попросить его завершиться. На Android следом почти всегда спрашивают про отмену корутин и про то, что станет с работой при уходе с экрана.
Как отвечать
Остановка в Java и Kotlin кооперативная: код внутри потока сам проверяет сигнал и выходит.
Thread.stop(): прерывал поток в произвольной точке и оставлял объекты в сломанном состоянии. На Android он бросаетUnsupportedOperationException, в свежих JDK тоже;- флаг
volatile boolean: поток проверяет его в цикле. Работает, но не будит поток, который спит или ждёт; interrupt(): выставляет флаг прерывания, аsleep(),wait(),join()и блокирующие очереди в ответ бросаютInterruptedException. Поймав его, либо завершайтесь, либо восстановите флаг черезThread.currentThread().interrupt();- блокирующий ввод-вывод: классический
InputStreamна прерывание не реагирует, разблокирует его только закрытие сокета или потока данных; ExecutorService:shutdown()дожидается текущих задач,shutdownNow()прерывает их,Future.cancel(true)прерывает одну задачу;- корутины:
job.cancel()или отмена всего скоупа. Функции kotlinx вродеdelay()проверяют отмену сами, а в долгом вычислительном цикле нужныensureActive(),isActiveилиyield(). Для блокирующего Java-кода естьrunInterruptible.
На Android лучше вообще не управлять жизнью потоков руками: viewModelScope и lifecycleScope отменяются вместе с владельцем, а работа, которая должна пережить закрытие приложения, уходит в WorkManager.
Где спотыкаются
Глотают InterruptedException пустым catch. Флаг сбрасывается, и поток работает дальше, будто сигнала не было.
Ловят всё через catch (e: Exception) или runCatching внутри корутины. Так перехватывается и CancellationException, и отмена ломается. Его нужно пробрасывать.
Запускают работу в GlobalScope или в своём потоке из Activity. После поворота экрана запрос продолжает выполняться и держит ссылку на уничтоженный экран.