Coroutines — conceptos clave, Job y Dispatchers en Kotlin

Autor: IT Sectr Publicado: 2026-03-16 Tiempo de lectura: 8 min

Las corrutinas (Coroutines) son hilos ligeros de Kotlin para programación asíncrona, disponibles a través de la librería kotlinx.coroutines. Según JetBrains Kotlin Documentation, 2026, Coroutines permiten suspender la ejecución de una función sin bloquear un hilo, a diferencia de los Thread tradicionales. Las corrutinas se ejecutan en un pool de hilos limitado, lo que las hace mil veces más ligeras que los hilos nativos. Kotlin Coroutines están completamente integradas con Android Jetpack, Retrofit, Room y otras bibliotecas populares del ecosistema Android.

Puntos Clave

  • Coroutines — hilos ligeros de Kotlin para código asíncrono sin bloqueo
  • Función suspend — una función que puede pausarse y reanudarse sin bloquear un hilo
  • Dispatcher determina el pool de hilos para la ejecución de la corrutina
  • Job — un descriptor de corrutina con soporte de cancelación y seguimiento de estado
  • CoroutineScope gestiona el ciclo de vida de las corrutinas y su cancelación al finalizar

Qué son las corrutinas Kotlin

Coroutines son un mecanismo de programación asíncrona en Kotlin, implementado en la librería kotlinx.coroutines. A diferencia de los hilos del sistema operativo, las corrutinas no están vinculadas a un hilo específico: pueden suspenderse en un hilo y reanudarse en otro. Un solo hilo puede ejecutar miles de corrutinas, alternando entre ellas con una sobrecarga mínima.

Las corrutinas aparecieron en Kotlin 1.3 (2018) como una función experimental y se volvieron estables en Kotlin 1.5 (2021). Coroutines resuelven el problema de callback hell de manera similar a async/await, pero proporcionan una API más rica: canales (Channel), Flow, manejo de excepciones en la jerarquía Job e integración directa con Android Lifecycle.

Según JetBrains (2025), cada corrutina consume alrededor de 100 bytes de memoria frente a 1+ MB de un hilo nativo. Esto permite ejecutar millones de corrutinas en una sola aplicación sin riesgo de OutOfMemoryError. Es precisamente la ligereza de las corrutinas lo que las convierte en la herramienta preferida para la asincronía en Android.

Cómo funcionan las corrutinas internamente

Cada corrutina Kotlin se compila en una máquina de estados mediante Continuation Passing Style (CPS). El compilador añade un parámetro Continuation oculto a cada función suspend. Continuation contiene el punto de reanudación y todas las variables locales. Cuando una corrutina se suspende, el runtime guarda Continuation, y cuando se reanuda, lo restaura en cualquier hilo disponible del pool de Dispatcher.

Funciones suspend: pausa y reanudación

suspend es una palabra clave de Kotlin que marca una función como suspendible. Esta función solo se puede llamar desde otra función suspend o desde una corrutina. Dentro de una función suspend, se pueden llamar a otras funciones suspend en cualquier orden, y cada punto de llamada es un punto potencial de suspensión.

La mecánica es simple: cuando una función suspend llama a otra función suspend, se suspende en ese punto, liberando el hilo. Una vez que la función llamada se completa, el runtime continúa la ejecución desde el lugar guardado. Esto se denomina cooperative cancellation: ningún hilo se bloquea.

  • Suspensión — la corrutina libera el hilo sin bloquearlo
  • Reanudación — la corrutina continúa desde donde se suspendió
  • Hilo — una corrutina puede suspenderse en el hilo A y reanudarse en el hilo B
  • Excepciones — se manejan mediante try/catch igual que en código síncrono

Importante: una función suspend no es asíncrona por defecto. El orden de ejecución sigue siendo secuencial si no se utilizan launch o async. suspend solo permite que la función se pause sin bloquear el hilo y forme parte del contexto de corrutina. Continuation Passing Style es un modelo de compilación donde cada función suspend recibe un callback Continuation oculto, y el compilador genera una máquina de estados para gestionar las suspensiones y reanudaciones.

CoroutineScope y Structured Concurrency

CoroutineScope es un contexto que define el ciclo de vida de las corrutinas. Todas las corrutinas deben lanzarse dentro de un scope. Cuando un scope se cancela (por ejemplo, cuando finaliza una Activity), todas sus corrutinas hijas se cancelan automáticamente. Esto evita fugas de tareas en segundo plano. Android Jetpack proporciona scopes predefinidos para cada componente: viewModelScope para ViewModel y lifecycleScope para Activity y Fragment, que se cancelan automáticamente al destruirse el componente correspondiente.

Structured Concurrency es un principio que garantiza que una corrutina no finalice hasta que todas sus corrutinas hijas hayan finalizado. La jerarquía Job forma un árbol: una corrutina raíz crea un parent job, los hijos crean child jobs. La cancelación de un parent job se propaga a todos los hijos. Structured Concurrency es una diferencia fundamental entre corrutinas y hilos.

ScopeDónde se usaCancelación
GlobalScopeSolo para tareas daemonNo se cancela automáticamente
viewModelScopeAndroid ViewModelAl limpiar el ViewModel
lifecycleScopeAndroid Activity/FragmentAl destruirse el lifecycle
coroutineScopeDentro de función suspendAl cancelar la job padre

SupervisorJob para manejo de errores

Un Job normal cancela todos los siblings cuando una corrutina hija falla. SupervisorJob es una excepción: un fallo en una corrutina hija no afecta a las demás. Esto es importante cuando varias tareas independientes se ejecutan en paralelo y una de ellas puede fallar sin necesidad de cancelar las otras.

Dispatchers y constructores de corrutinas

Dispatchers determinan en qué hilos se ejecutan las corrutinas. Dispatchers.Main — el hilo principal de UI de Android. Dispatchers.IO — un pool para operaciones bloqueantes (red, disco). Dispatchers.Default — para tareas intensivas en CPU. Dispatchers.Unconfined — comienza en el hilo actual pero no garantiza permanecer en él. Elegir el Dispatcher correcto es crítico para el rendimiento: una tarea IO en Default bloqueará el pool de cómputo, mientras que una tarea de CPU en IO creará hilos innecesarios.

withContext — una función para cambiar de Dispatcher dentro de una corrutina. Por ejemplo, una función suspend que analiza JSON puede cambiar a Dispatchers.Default para el cómputo y volver a Dispatchers.Main para actualizar la UI. withContext es el constructor más utilizado en el desarrollo Android.

Tres constructores principales de corrutinas

launch — lanza una corrutina, devuelve un Job, no devuelve un resultado (fire-and-forget). async — lanza una corrutina, devuelve un Deferred del que se puede obtener el resultado mediante await. runBlocking — bloquea el hilo actual para ejecutar una corrutina (solo para pruebas y funciones main). Elección del constructor depende del escenario: launch es adecuado para eventos y actualizaciones, async para tareas con resultado, runBlocking solo para pruebas o puntos de entrada.

Ejemplos de código con corrutinas en Kotlin

Consideremos tres escenarios prácticos: una corrutina básica con launch, una llamada paralela con async y el manejo de errores con SupervisorJob.

Lanzar una corrutina con launch

viewModelScope.launch lanza una corrutina en el contexto del ViewModel. Cuando el ViewModel se limpia, la corrutina se cancela automáticamente.

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

Peticiones paralelas con async

coroutineScope con async lanza tres peticiones en paralelo. Los resultados se recogen mediante .await(). Si alguna petición falla, todas se cancelan.

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

Manejo de errores con SupervisorJob

SupervisorJob permite que cada corrutina finalice de forma independiente. Un error en una petición no cancela las demás.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

Corrutinas vs hilos: comparación y escenarios

Hilos (Thread) son un primitivo del sistema operativo. Cada hilo tiene su propia pila (~1 MB) y requiere una llamada al sistema para crearse y cambiarse. Corrutinas son un primitivo del lenguaje, no vinculado al SO. Utilizan Continuation para guardar el estado y cambian a nivel de runtime sin llamadas al sistema.

  • Memoria — hilo ~1 MB, corrutina ~100 bytes. Una diferencia de 10 000 veces
  • Creación — hilo ~1 µs syscall, corrutina ~0.01 µs a nivel JVM
  • Cambio — hilo ~0.1 µs (syscall), corrutina ~0.001 µs (continuation)
  • Máximo — miles de hilos vs millones de corrutinas por dispositivo
  • Cancelación — un hilo no se puede cancelar externamente (Thread.stop obsoleto), una corrutina sí mediante Job.cancel()

Según Google (2025), usar corrutinas en lugar de hilos reduce el consumo de memoria para tareas en segundo plano en aplicaciones Android en un 90–95%. Todas las bibliotecas modernas de Android (Retrofit, Room, WorkManager) tienen soporte integrado para corrutinas mediante funciones suspend. Ktor (framework cliente HTTP de JetBrains) también está construido completamente sobre corrutinas, proporcionando funciones suspend para cada petición sin API de callbacks. Room admite corrutinas mediante funciones suspend en DAO, lo que permite ejecutar consultas a la BD sin bloquear el hilo principal.

Cuándo usar hilos en lugar de corrutinas

Los hilos siguen siendo necesarios para código nativo a través de JNI, llamadas bloqueantes de CPU-intensive sin límite de tiempo (renderizado de vídeo, simulaciones) y al integrarse con bibliotecas C. Para todo lo demás — corrutinas.

Preguntas Frecuentes

¿En qué se diferencia una corrutina de un hilo?

Corrutina es una unidad de trabajo suspendible que se ejecuta en un hilo existente. Un hilo es un recurso del sistema con su propia pila. Las corrutinas son miles de veces más ligeras que los hilos y no bloquean recursos al suspenderse.

¿Qué es Dispatchers.IO y en qué se diferencia de Default?

Dispatchers.IO está diseñado para operaciones de E/S bloqueantes (red, archivos) y puede crear nuevos hilos cuando sea necesario. Dispatchers.Default tiene un pool de tamaño fijo (número de núcleos de CPU) para cómputos intensivos en CPU.

¿Cómo cancelar una corrutina en ejecución?

Job.cancel() cancela la corrutina y todos sus hijos. Para comprobar la cancelación dentro de una corrutina, use ensureActive() — lanza una CancellationException si la corrutina está cancelada.

¿Se pueden usar corrutinas con RxJava?

Sí — a través de la librería kotlinx-coroutines-rx3. Proporciona funciones awaitSingle, awaitFirst y otras para convertir Observable/Single en funciones suspend y viceversa mediante flowable.

¿Qué es Flow en corrutinas?

Flow es un flujo de datos asíncrono en frío, el equivalente en corrutinas de RxJava Observable. Flow emite valores secuencialmente y finaliza con una excepción o éxito. Soporta map, filter, catch y otros operadores.

Resumen

  • Coroutines — hilos ligeros de Kotlin con suspensión sin bloqueo mediante Continuation Passing Style
  • suspend — la palabra clave para marcar funciones suspendibles
  • Dispatchers gestionan el pool de hilos: Main, IO, Default respectivamente
  • CoroutineScope vincula el ciclo de vida de las corrutinas a un componente (Activity, ViewModel)
  • launch inicia una corrutina sin resultado, async/await — con resultado
  • Structured Concurrency garantiza la cancelación jerárquica de las corrutinas hijas
  • Corrutinas vs hilos — las corrutinas son 10 000 veces más ligeras y son el estándar para Android

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también