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

Какие знаешь методы проверки завершения корутины?

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

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

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

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

Методы проверки завершения корутины в Kotlin

В Kotlin Coroutines существует несколько ключевых методов для определения состояния выполнения и проверки завершения корутины. Эти подходы варьируются от низкоуровневых проверок состояния до использования встроенных механизмов отмены и обработки исключений.

Основные подходы к проверке завершения

1. Использование свойства isActive

Свойство isActive доступно внутри корутины через coroutineScope или CoroutineScope и указывает, активна ли корутина.

suspend fun checkWithIsActive() {
    coroutineScope {
        val job = launch {
            repeat(1000) { i ->
                if (!isActive) {
                    println("Корутина была отменена")
                    return@launch
                }
                println("Работаем: $i")
                delay(100)
            }
        }
        
        delay(350)
        job.cancel()
    }
}

2. Проверка состояния Job

Каждая корутина связана с объектом Job, который предоставляет информацию о состоянии выполнения.

suspend fun checkJobState() {
    val job = GlobalScope.launch {
        delay(1000)
        println("Корутина завершена")
    }
    
    // Проверка состояния через свойства Job
    println("isActive: ${job.isActive}")
    println("isCompleted: ${job.isCompleted}")
    println("isCancelled: ${job.isCancelled}")
    
    job.join() // Ожидание завершения
    println("После join: isCompleted = ${job.isCompleted}")
}

Практические методы проверки

3. Использование функции join()

Метод join() приостанавливает вызывающую корутину до завершения целевой корутины.

suspend fun usingJoin() {
    val job = launch {
        delay(2000)
        println("Длительная операция завершена")
    }
    
    println("Ожидаем завершения корутины...")
    job.join() // Приостановка здесь до завершения job
    println("Корутина завершилась, продолжаем работу")
}

4. Комбинация cancel() и join()

Для гарантированной отмены и ожидания завершения.

suspend fun cancelAndJoin() {
    val job = launch {
        repeat(1000) { i ->
            println("Итерация $i")
            delay(500)
        }
    }
    
    delay(1300)
    job.cancel() // Запрос отмены
    job.join()   // Ожидание фактического завершения
    println("Корутина полностью остановлена")
}

5. Обработка исключений через try-catch

Корутины генерируют CancellationException при отмене, что можно использовать для определения завершения.

suspend fun handleCancellation() {
    val job = GlobalScope.launch {
        try {
            delay(3000)
            println("Успешное завершение")
        } catch (e: CancellationException) {
            println("Корутина была отменена: ${e.message}")
        } finally {
            println("Финальные действия при отмене")
        }
    }
    
    delay(1500)
    job.cancel("Причина отмены")
}

6. Использование withTimeout и withTimeoutOrNull

Встроенные функции для ограничения времени выполнения.

suspend fun usingTimeout() {
    // withTimeout бросает TimeoutCancellationException
    try {
        withTimeout(1300) {
            repeat(1000) { i ->
                println("Работа: $i")
                delay(500)
            }
        }
    } catch (e: TimeoutCancellationException) {
        println("Время выполнения истекло")
    }
    
    // withTimeoutOrNull возвращает null при таймауте
    val result = withTimeoutOrNull(1300) {
        delay(1000)
        "Результат"
    }
    println("Результат: $result") // null если не успел
}

7. Callback-обработчики состояния Job

Добавление обработчиков через invokeOnCompletion.

fun usingInvokeOnCompletion() {
    val job = GlobalScope.launch {
        delay(2000)
        println("Работа выполнена")
    }
    
    job.invokeOnCompletion { cause ->
        when {
            cause == null -> println("Корутина завершилась успешно")
            cause is CancellationException -> println("Корутина отменена")
            else -> println("Корутина завершилась с ошибкой: $cause")
        }
    }
}

Продвинутые техники

8. Использование SupervisorJob и наблюдение за состоянием

suspend fun monitorCoroutineState() {
    val supervisorJob = SupervisorJob()
    val scope = CoroutineScope(Dispatchers.IO + supervisorJob)
    
    val jobs = mutableListOf<Job>()
    
    repeat(3) { index ->
        val job = scope.launch {
            delay((index + 1) * 1000L)
            println("Корутина $index завершена")
        }
        jobs.add(job)
    }
    
    // Проверка состояния всех корутин
    while (jobs.any { it.isActive }) {
        delay(500)
        val activeCount = jobs.count { it.isActive }
        println("Активных корутин: $activeCount")
    }
}

9. Комбинация async/await для результата

Для корутин, которые возвращают результат.

suspend fun usingAsyncAwait() {
    val deferred = GlobalScope.async {
        delay(1500)
        42
    }
    
    // isCompleted для Deferred
    println("Deferred completed: ${deferred.isCompleted}")
    
    try {
        val result = deferred.await() // Приостановка до получения результата
        println("Получен результат: $result")
    } catch (e: Exception) {
        println("Ошибка при выполнении: $e")
    }
}

Ключевые рекомендации

  • Для простых случаев используйте join() для ожидания завершения
  • При необходимости отмены применяйте комбинацию cancelAndJoin()
  • Для обработки таймаутов предпочитайте withTimeoutOrNull как более безопасный вариант
  • Для реактивного подхода используйте invokeOnCompletion для callback-обработки
  • Всегда проверяйте isActive внутри длительных циклов в корутинах для корректной реакции на отмену
  • Помните о структурированной конкурентности — предпочитайте coroutineScope вместо глобальных scope для автоматического управления жизненным циклом

Выбор конкретного метода зависит от контекста: нужно ли просто дождаться завершения, обработать отмену, получить результат или ограничить время выполнения. Правильное использование этих методов обеспечивает надежное управление жизненным циклом корутин и предотвращает утечки ресурсов.