Introducción a la concurrencia y el multihilo en Kotlin
Las aplicaciones modernas requieren cada vez más la ejecución de múltiples tareas simultáneamente, desde el procesamiento de solicitudes de red hasta el trabajo con bases de datos. En el lenguaje Kotlin, que se utiliza activamente para el desarrollo en Android, aplicaciones de servidor (Ktor, Spring) e incluso soluciones de escritorio, se han implementado potentes herramientas para trabajar con concurrencia y multihilo.
En este artículo, analizaremos los conceptos clave: los hilos tradicionales (Threads), las corrutinas (Coroutines) —el enfoque moderno para la asincronía en Kotlin—, así como los mecanismos de sincronización. Aprenderá cuándo usar hilos y cuándo usar corrutinas, y obtendrá ejemplos de código listos para usar.
1. Hilos tradicionales (Threads) en Kotlin
Kotlin es totalmente compatible con Java, por lo que puede usar las clases estándar Thread y Runnable. Sin embargo, Kotlin añade azúcar sintáctico, haciendo que el código sea más conciso.
Creación e inicio de un hilo
La forma básica de crear un hilo es pasar una lambda al constructor de Thread:
fun main() { val thread = Thread { println("Hilo iniciado: ${Thread.currentThread().name}") for (i in 1..5) { println("Cuenta: $i") Thread.sleep(500) } } thread.start() println("El hilo principal continúa su trabajo") thread.join() // esperamos a que termine el hilo println("Hilo principal finalizado")}En este ejemplo, creamos un hilo que imprime números del 1 al 5 con un retardo de 500 ms. El método join() obliga al hilo principal a esperar a que termine el hilo secundario.
Problemas de los hilos
- Alto consumo de recursos — cada hilo requiere una pila de memoria separada (normalmente 1 MB).
- Complejidad de sincronización — al trabajar con datos compartidos, es fácil provocar una condición de carrera (race condition).
- Cantidad limitada — en un solo dispositivo no se pueden iniciar decenas de miles de hilos sin perder rendimiento.
Es por esto que en Kotlin aparecieron las corrutinas, una alternativa más ligera.
2. Corrutinas (Coroutines) — concurrencia moderna en Kotlin
Las corrutinas son hilos ligeros que pueden suspender su ejecución sin bloquear el hilo del sistema. Son la herramienta principal para la programación asíncrona en Kotlin.
Configuración de corrutinas
Para trabajar con corrutinas, es necesario añadir la dependencia en build.gradle.kts:
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")}Ejemplo básico de corrutina
import kotlinx.coroutines.*
fun main() = runBlocking { println("Inicio del trabajo en el hilo: ${Thread.currentThread().name}")
launch { // inicio de una nueva corrutina delay(1000) // retardo no bloqueante println("Corrutina: ${Thread.currentThread().name}") }
println("La corrutina principal continúa su trabajo") delay(2000) // esperamos a que termine la corrutina secundaria println("Fin")}Puntos clave:
runBlocking— puente entre el código normal y las corrutinas (bloquea el hilo actual).launch— inicia una corrutina que no devuelve un resultado.delay— retardo no bloqueante, a diferencia deThread.sleep().
Async y await para obtener un resultado
Si la corrutina debe devolver un valor, use async:
fun main() = runBlocking { val deferred1 = async { delay(1000) "Resultado 1" } val deferred2 = async { delay(500) "Resultado 2" }
println("Esperando resultados...") val result1 = deferred1.await() val result2
```