← Назад к вопросам
Отменятся ли дочерние корутины при отмене родительской
3.0 Senior🔥 171 комментариев
#Многопоточность и асинхронность
Комментарии (1)
🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Отмена дочерних корутин при отмене родительской
Да, в Kotlin Coroutines дочерние корутины автоматически отменяются при отмене родительской корутины. Это одно из фундаментальных свойств иерархической структуры корутин, обеспечивающее корректное управление жизненным циклом и ресурсами.
Механизм иерархической отмены
Когда вы запускаете корутину внутри другой корутины (например, с помощью launch или async в рамках coroutineScope или supervisorScope), между ними устанавливается отношение родитель-SD-ребёнок. При отмене родительской корутины:
- Родительская корутина немедленно переходит в состояние отмены (
Cancelling). - Все её непосредственные дочерние корутины рекурсивно получают сигнал об отмене.
- Родительская корутина ожидает завершения всех дочерних корутин (их отмены или нормального завершения) перед тем как перейти в состояние отменена (
Cancelled).
Практический пример
Рассмотрим код, демонстрирующий это поведение:
import kotlinx.coroutines.*
fun main() = runBlocking {
val parentJob = launch {
println("Родительская корутина начата")
launch {
println("Дочерняя корутина 1 начата")
delay(3000)
println("Дочерняя корутина 1 завершена") // Не будет выполнено
}
launch {
println("Дочерняя корутина 2 начата")
delay(5000)
println("Дочерняя корутина 2 завершена") // Не будет выполнено
}
delay(1000)
println("Родительская корутина завершена")
}
delay(500)
println("Отменяем родительскую корутину")
parentJob.cancel() // Отменяем родительскую корутину
parentJob.join()
println("Программа завершена")
}
Результат выполнения:
Родительская корутина начата
Дочерняя корутина 1 начата
Дочерняя корутина 2 начата
Отменяем родительскую корутину
Программа завершена
Как видно, ни одна из дочерних корутин не достигает своих завершающих сообщений, поскольку они были отменены вместе с родительской.
Важные нюансы и исключения
- Использование SupervisorJob: Если дочерняя корутина запущена в контексте
SupervisorJobили с использованиемsupervisorScope, отмена одной дочерней корутины не влияет на другие дочерние корутины, и отмена родительской корутины также приводит к отмене всех дочерних.
import kotlinx.coroutines.*
fun main() = runBlocking {
val parentJob = launch(SupervisorJob()) {
println("Родитель с SupervisorJob начат")
launch {
println("Дочерняя 1 начата")
delay(3000)
println("Дочерняя 1 завершена")
}
launch {
println("Дочерняя 2 начата")
delay(1000)
throw RuntimeException("Ошибка в дочерней 2") // Не отменяет другие дочерние
}
delay(2000)
}
delay(1500)
parentJob.cancel() // Всё равно отменяет все дочерние корутины
parentJob.join()
}
- Корутины в другом контексте: Если дочерняя корутина запущена с явно указанным контекстом, не являющимся дочерним по отношению к родительской, иерархическая отмена может не сработать:
import kotlinx.coroutines.*
fun main() = runBlocking {
val parentJob = launch {
println("Родитель начат")
// Эта корутина НЕ будет автоматически отменена при отмене родителя
launch(Job()) { // Явно созданный Job, не связанный иерархически
println("Изолированная корутина начата")
delay(3000)
println("Изолированная корутина завершена") // Будет выполнено!
}
delay(1000)
println("Родитель завершён")
}
delay(500)
parentJob.cancel()
delay(3500) // Ждём завершения изолированной корутины
}
- Обработка отмены: Дочерние корутины должны корректно реагировать на отмену. Функции приостановки Kotlin Coroutines (like
delay,withContext, etc.) проверяют статус отмены и выбрасываютCancellationException, но в CPU.