← Назад к вопросам

Что происходит с ресурсами используемыми в потоке при его отмене

1.0 Junior🔥 101 комментариев
#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ресурсы и отмена потока в Android (Kotlin Coroutines)

При работе с корутинами в Kotlin управление ресурсами во время отмены потока (Job) является критически важным для предотвращения утечек памяти, некорректного состояния и других проблем. Механизм отмены в корутинах кооперативный — это означает, что сама корутина должна реагировать на запрос отмены и корректно освобождать ресурсы.

Что происходит при отмене потока

Когда вызывается job.cancel(), происходит следующее:

  1. Состояние Job меняется на isCancelled.
  2. Корутина не прекращается немедленно. Вместо этого она получает сигнал через исключение CancellationException.
  3. Корутина должна кооперативно завершить работу, проверяя статус отмены и освобождая ресурсы.

Управление ресурсами при отмене

Для корректного освобождения ресурсов используются следующие подходы:

1. Использование try-catch с CancellationException

suspend fun loadDataFromNetwork() {
    val connection = openNetworkConnection() // ресурс
    try {
        // выполняем работу
        val data = connection.readData()
        processData(data)
    } catch (e: CancellationException) {
        // освобождаем ресурсы при отмене
        connection.close()
        throw e // важно перевыбросить исключение
    } finally {
        // finally выполняется даже при отмене
        connection.close()
    }
}

2. Использование suspendCancellableCoroutine

suspend fun awaitCallback(): Result {
    return suspendCancellableCoroutine { continuation ->
        val callback = Callback { result ->
            continuation.resume(result)
        }
        
        // регистрируем callback в системе
        
        // ОЧЕНЬ ВАЖНО: освобождаем ресурсы при отмене
        continuation.invokeOnCancellation {
            // удаляем callback, закрываем соединения
            system.unregisterCallback(callback)
        }
    }
}

3. Использование DisposableHandle и withContext

suspend fun supervisedOperation() {
    withContext(NonCancellable) {
        // этот блок НЕ будет отменен, можно безопасно освободить ресурсы
        cleanupResources()
    }
}

Автоматическое освобождение ресурсов

Для некоторых типов ресурсов существуют автоматические механизмы:

  • close() на объектах с AutoCloseable — могут быть использованы в finally.
  • Ресурсы, управляемые жизненным циклом (Lifecycle) — например, в Android ViewModelScope автоматически очищает корутины при очистке ViewModel.
  • CoroutineScope с SupervisorJob — позволяет контролировать отмену группы корутин.

Пример управления несколькими ресурсами

suspend fun complexOperation() {
    val dbConnection = openDatabase()
    val fileStream = openFileStream()
    val networkCallback = registerNetworkListener()
    
    try {
        performWork(dbConnection, fileStream, networkCallback)
    } finally {
        // гарантированное освобождение всех ресурсов
        dbConnection.close()
        fileStream.close()
        networkCallback.unregister()
    }
}

Проблемы и рекомендации

  1. Не забывайте перевыбрасывать CancellationException — если вы его перехватываете и не перевыбрасываете, корутина не узнает о отмене.
  2. Освобождайте ресурсы в finally — блок finally выполняется даже при отмене корутины.
  3. Избегайте долгих операций после отмены — после получения CancellationException следует быстро освободить ресурсы и завершить работу.
  4. Используйте invokeOnCancellation для callback-based API — это специальный механизм для асинхронных операций.

Связь с жизненным циклом Android

В Android корутины часто запускаются в ViewModelScope, LifecycleScope или Fragment/view lifecycleScope. При уничтожении компонента:

  • Scope автоматически вызывает cancel() на всех корутинах.
  • Корутины должны освободить ресурсы (закрыть соединения, остановить операции).
  • Если корутина не освободит ресурсы, могут возникнуть утечки памяти или активные операции без нужного контекста.

Ключевой вывод: отмена корутины — это сигнал, а не немедленная остановка. Разработчик обязан обеспечить кооперативное освобождение всех ресурсов через механизмы finally, invokeOnCancellation и правильную обработку CancellationException.