Sobes.tech
Middle

Quali elementi di multithreading fornisce Kotlin?

sobes.tech AI

Risposta dell'AI

Kotlin fornisce i seguenti elementi di concorrenza:

  • Coroutines: Thread leggeri basati su funzioni sospese. Consentono l'esecuzione asincrona e non bloccante del codice.
  • Costruttori di coroutine: Funzioni che avviano coroutine. Principali: launch (avvia una coroutine senza restituire un valore), async (avvia una coroutine e restituisce un Deferred, che può essere atteso per ottenere il risultato).
    // Esempio di utilizzo di launch
    GlobalScope.launch {
        println("Ciao dalla coroutine ${Thread.currentThread().name}")
    }
    
    // Esempio di utilizzo di async
    val deferred = GlobalScope.async {
        delay(1000) // Simula un'operazione lunga
        "Risultato"
    }
    val result = runBlocking { deferred.await() } // Attende il risultato
    
  • Dispatchers: Determinano su quale pool di thread verrà eseguita la coroutine. Principali:
    • Dispatchers.Default: Pool generale per compiti intensivi in CPU.
    • Dispatchers.IO: Pool per operazioni di input/output bloccanti (file, rete).
    • Dispatchers.Main: Dispatcher per il thread dell'interfaccia utente sulle piattaforme appropriate (Android, Swing).
    • Dispatchers.Unconfined: La coroutine viene avviata nel thread corrente, ma può essere ripresa in qualsiasi thread.
    GlobalScope.launch(Dispatchers.IO) {
        // Esecuzione di input/output
    }
    
  • runBlocking: Funzione costruttore di coroutine che blocca il thread corrente fino al completamento della coroutine. Viene usata per combinare codice bloccante e non bloccante, spesso nei test o nelle funzioni main.
    runBlocking {
        launch {
            delay(500)
            println("Completato in ${Thread.currentThread().name}")
        }
        println("Avviato in ${Thread.currentThread().name}")
    }
    
  • Funzioni suspend: Funzioni il cui esecuzione può essere sospesa e ripresa. Possono essere chiamate solo da altre funzioni suspend o costruttori di coroutine.
    suspend fun doSomething() {
        delay(100) // Esempio di sospensione
    }
    
  • Job: Handle per una coroutine in esecuzione. Fornisce metodi per gestire il ciclo di vita della coroutine (annullare, attendere il completamento).
    val job = GlobalScope.launch {
       // Operazione lunga
    }
    job.cancel() // Annulla la coroutine
    runBlocking { job.join() } // Attende il completamento
    
  • CoroutineScope: Definisce un ambito per le coroutine. Le coroutine lanciate in un ambito specifico vengono automaticamente annullate alla cancellazione dell'ambito. Aiuta a gestire il ciclo di vita delle coroutine.
    val scope = CoroutineScope(Dispatchers.Default)
    scope.launch {
        // Coroutine in questo ambito
    }
    scope.cancel() // Annulla tutte le coroutine in questo ambito
    
  • Canali (Channel): Primitive per il trasferimento sicuro di dati tra coroutine. I canali possono essere unidirezionali (solo invio o ricezione) o bidirezionali.
    import kotlinx.coroutines.channels.Channel
    
    val channel = Channel<Int>()
    
    runBlocking {
        launch {
            for (x in 1..5) channel.send(x * x)
            channel.close() // È importante chiudere il canale
        }
        launch {
            for (y in channel) println(y)
        }
    }
    
  • Mutex (Mutex): Primitive di sincronizzazione per garantire accesso esclusivo a una risorsa condivisa. Garantisce la sicurezza dei thread, permettendo a una sola coroutine di possedere il mutex in un dato momento.
    import kotlinx.coroutines.sync.Mutex
    import kotlinx.coroutines.sync.withLock
    
    val mutex = Mutex()
    var counter = 0
    
    suspend fun incrementCounter() {
        mutex.withLock {
            counter++
        }
    }
    
  • Stati (StateFlow, SharedFlow): Primitive per lavorare con flussi di dati nel contesto della programmazione reattiva e concorrente. StateFlow rappresenta un flusso "freddo" con lo stato attuale, mentre SharedFlow è un flusso "caldo" per la diffusione di dati.