Concurrence et multithreading en Kotlin : de A à Z

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Concurrence et multithreading en Kotlin : de A à Z



Les applications modernes nécessitent de plus en plus souvent l'exécution de plusieurs tâches simultanément. En Kotlin, comme dans d'autres langages JVM, le multithreading est traditionnellement implémenté via la classe Thread. Cependant, le langage propose un outil bien plus puissant et élégant : les coroutines. Dans cet article, nous aborderons tous les aspects de la concurrence et du multithreading en Kotlin : des concepts de base aux techniques avancées.



1. Bases du multithreading : Thread et Runnable



Commençons par l'approche classique. En Kotlin, comme en Java, vous pouvez créer un thread directement :



fun main() {    val thread = Thread {        for (i in 1..5) {            println("Thread : $i")            Thread.sleep(500)        }    }    thread.start()    println("Thread principal terminé")}


Cependant, la gestion manuelle des threads présente des inconvénients :

  • Frais généraux élevés — la création et la destruction de threads sont coûteuses.
  • Complexité de synchronisation — il est facile de provoquer une race condition.
  • Nombre limité de threads — le système ne peut créer qu'un nombre limité de threads.


Pour synchroniser l'accès aux données partagées, on utilise le mot-clé synchronized ou les verrous ReentrantLock :



class Counter {    private var count = 0    @Synchronized    fun increment() {        count++    }}


2. Les coroutines — une approche moderne de la concurrence



Les coroutines sont des threads légers qui résolvent les problèmes du multithreading classique. Elles ne sont pas liées aux threads système et peuvent s'exécuter sur un seul thread, en basculant entre les tâches.



2.1. Première coroutine



Pour travailler avec les coroutines, vous devez ajouter la dépendance org.jetbrains.kotlinx:kotlinx-coroutines-core. Exemple d'une coroutine simple :



import kotlinx.coroutines.*

fun main() = runBlocking { launch { delay(1000L) println("Monde !") } println("Bonjour,")}


Ici, runBlocking est un pont entre le code normal et les coroutines. launch démarre une nouvelle coroutine, et delay est l'équivalent de Thread.sleep(), mais sans bloquer le thread.



2.2. Fonctions suspend



Le mot-clé suspend permet de suspendre l'exécution d'une fonction sans bloquer le thread :



suspend fun fetchData(): String {    delay(2000L) // simulation d'une requête réseau    return "Données reçues"}

fun main() = runBlocking { val result = async { fetchData() } println("Attente...") println(result.await())}


2.3. Concurrence structurée



Kotlin prend en charge la concurrence structurée — toutes les coroutines enfants se terminent automatiquement avant la fin de la coroutine parente :



fun main() = runBlocking {    coroutineScope {        launch {            delay(1000L)            println("Tâche 1")        }        launch {            delay(500L)            println("Tâche 2")        }    }    println("Toutes les tâches sont terminées")}


3. Techniques avancées : Channel, Flow et Dispatchers



3.1. Canaux (Channel)



Les canaux permettent d'échanger des données entre les coroutines. C'est l'équivalent d'une file d'attente :



fun main() = runBlocking {    val channel = Channel<Int>()        launch {        for (i in 1..5) {            channel.send(i * i)        }        channel.close()    }        for (value in channel) {        println(value)    }}


3.2. Flow — flux de données froids



Flow est un flux réactif qui émet des valeurs à la demande :



fun simpleFlow(): Flow<Int> = flow {    for (i in 1..3) {        delay(                

Blogs

Book Recommendations