Introduction à la concurrence et au multithreading en Kotlin
Les applications modernes nécessitent de plus en plus souvent l'exécution de plusieurs tâches simultanément — du traitement des requêtes réseau au travail avec les bases de données. Dans le langage Kotlin, qui est activement utilisé pour le développement Android, les applications serveur (Ktor, Spring) et même les solutions desktop, des outils puissants pour la concurrence et le multithreading sont implémentés.
Dans cet article, nous allons examiner les concepts clés : les threads traditionnels (Threads), les coroutines (Coroutines) — l'approche moderne de l'asynchrone en Kotlin, ainsi que les mécanismes de synchronisation. Vous apprendrez quand utiliser les threads et quand utiliser les coroutines, et vous obtiendrez des exemples de code prêts à l'emploi.
1. Threads traditionnels (Threads) en Kotlin
Kotlin est entièrement compatible avec Java, vous pouvez donc utiliser les classes standard Thread et Runnable. Cependant, Kotlin ajoute du sucre syntaxique, rendant le code plus concis.
Création et lancement d'un thread
La méthode de base pour créer un thread est de passer une lambda au constructeur Thread :
fun main() { val thread = Thread { println("Thread lancé : ${Thread.currentThread().name}") for (i in 1..5) { println("Compteur : $i") Thread.sleep(500) } } thread.start() println("Le thread principal continue son travail") thread.join() // attend la fin du thread println("Thread principal terminé")}Dans cet exemple, nous avons créé un thread qui affiche les nombres de 1 à 5 avec un délai de 500 ms. La méthode join() force le thread principal à attendre la fin du thread enfant.
Problèmes des threads
- Consommation élevée de ressources — chaque thread nécessite une pile mémoire distincte (généralement 1 Mo).
- Complexité de synchronisation — lors du travail avec des données partagées, il est facile de créer une condition de concurrence (race condition).
- Nombre limité — on ne peut pas lancer des dizaines de milliers de threads sur un seul appareil sans perte de performance.
C'est pourquoi les coroutines sont apparues en Kotlin — une alternative plus légère.
2. Coroutines (Coroutines) — la concurrence moderne en Kotlin
Les coroutines sont des threads légers qui peuvent suspendre leur exécution sans bloquer le thread système. Elles sont l'outil principal pour la programmation asynchrone en Kotlin.
Ajout des coroutines
Pour travailler avec les coroutines, il est nécessaire d'ajouter la dépendance dans build.gradle.kts :
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")}Exemple de base d'une coroutine
import kotlinx.coroutines.*
fun main() = runBlocking { println("Début du travail dans le thread : ${Thread.currentThread().name}")
launch { // lancement d'une nouvelle coroutine delay(1000) // délai non bloquant println("Coroutine : ${Thread.currentThread().name}") }
println("La coroutine principale continue son travail") delay(2000) // attend la fin de la coroutine enfant println("Fin")}Points clés :
runBlocking— pont entre le code normal et les coroutines (bloque le thread actuel).launch— lance une coroutine qui ne retourne pas de résultat.delay— délai non bloquant, contrairement àThread.sleep().
Async et await pour obtenir un résultat
Si la coroutine doit retourner une valeur, utilisez async :
fun main() = runBlocking { val deferred1 = async { delay(1000) "Résultat 1" } val deferred2 = async { delay(500) "Résultat 2" }
println("Attente des résultats...") val result1 = deferred1.await() val result2