Concurrencia y multihilo en Kotlin: nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Concurrencia y multihilo en Kotlin: nivel avanzado

\n

En el desarrollo moderno con Kotlin, especialmente para aplicaciones de servidor y Android, una gestión adecuada de la concurrencia es clave para el rendimiento y la capacidad de respuesta. A nivel avanzado, no basta con simplemente lanzar una corrutina. Es necesario comprender cómo sincronizar eficazmente el acceso a los datos, gestionar los hilos y evitar los bloqueos "infernales". En este artículo, analizaremos técnicas avanzadas: desde los detalles de kotlinx.coroutines hasta colecciones thread-safe y canales.

\n\n

1. Inmersión profunda en corrutinas: Structured Concurrency y Scopes

\n

La base del trabajo avanzado es la Structured Concurrency. Este es un principio por el cual el ciclo de vida de una corrutina está vinculado a un ámbito (scope). Si la corrutina padre se cancela, todas sus tareas hijas finalizan automáticamente. Esto evita fugas de memoria y procesos incontrolados.

\n

A nivel avanzado, debe crear sus propios scopes, en lugar de depender del GlobalScope global.

\n\n
import kotlinx.coroutines.*\nimport kotlin.coroutines.CoroutineContext\n\nclass DataRepository {\n    // Scope propio con dispatcher y manejador de excepciones\n    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler { _, throwable ->\n        println("Error no manejado: ${throwable.message}")\n    })\n\n    fun loadData() {\n        scope.launch {\n            // corrutinas hijas\n            val data = async { fetchFromNetwork() }\n            val cache = async { loadFromCache() }\n            process(data.await(), cache.await())\n        }\n    }\n\n    fun cleanup() {\n        scope.cancel() // cancela todas las corrutinas en el scope\n    }\n}
\n\n

Utilice SupervisorJob cuando el fallo de una corrutina hija no deba cancelar a las demás. Esto es crítico para capas de UI o solicitudes paralelas independientes.

\n\n

2. Colecciones Thread-Safe y operaciones atómicas

\n

Incluso con corrutinas, si trabaja con datos mutables compartidos, necesita sincronización. Kotlin ofrece varios enfoques:

\n
    \n
  • Tipos atómicos (AtomicInteger, AtomicReference) — para contadores y banderas simples.
  • \n
  • Colecciones Thread-Safe (ConcurrentHashMap, CopyOnWriteArrayList) — para estructuras complejas.
  • \n
  • Mutex de kotlinx.coroutines — para secciones críticas dentro de corrutinas.
  • \n
\n\n
import kotlinx.coroutines.*\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass SafeCounter {\n    private val mutex = Mutex()\n    private var counter = 0\n\n    suspend fun increment() {\n        mutex.withLock {\n            counter++ // sección crítica\n        }\n    }\n\n    fun getCounter(): Int = counter\n}\n\nclass CacheManager {\n    private val cache = ConcurrentHashMap<String, String>()\n    private val hitCount = AtomicInteger(0)\n\n    fun put(key: String, value: String) {\n        cache[key] = value\n    }\n\n    fun get(key: String): String? {\n        val result = cache[key]\n        if (result != null) hitCount.incrementAndGet()\n        return result\n    }\n}
\n\n

Importante: Mutex es una función suspend, por lo que no bloquea el hilo, sino que suspende la corrutina. Esto es más eficiente que synchronized.

\n\n

3. Canales (Channels) y Flow: flujos de datos reactivos

\n

Para transferir datos entre corrutinas, utilice Channels (análogo a BlockingQueue para corrutinas) y Flow (flujo asíncrono frío).

\n\n

Canales: Productor-Consumidor

\n
import kotlinx.coroutines.channels.*\nimport kotlinx.coroutines.*\n\nfun Corout                

Blogs

Book Recommendations