Concorrência e Multithreading em Kotlin: Nível Avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Concorrência e Multithreading em Kotlin: Nível Avançado



No desenvolvimento moderno, o gerenciamento eficaz da concorrência é a chave para criar aplicações rápidas e responsivas. Kotlin, graças ao suporte integrado a coroutines, oferece um conjunto de ferramentas poderoso e flexível que vai muito além das threads padrão do Java. Neste artigo, exploraremos conceitos avançados de concorrência e multithreading em Kotlin, incluindo o trabalho com Channel, Flow, Mutex e os detalhes dos agendadores.



1. Coroutines: Mais Fundo que o Básico



Coroutines são threads leves que permitem escrever código assíncrono em estilo imperativo. No entanto, em nível avançado, é importante entender como funcionam os dispatchers e os contextos de coroutines.



Agendadores (Dispatchers)

A escolha do dispatcher correto é crítica para o desempenho:

  • Dispatchers.Default — para tarefas intensivas em CPU (por padrão, usa um pool de threads igual ao número de núcleos do processador).
  • Dispatchers.IO — para operações de entrada/saída (rede, arquivos). O pool de threads pode se expandir até 64 threads (ou mais, dependendo da configuração).
  • Dispatchers.Main — para a thread da UI (Android, JavaFX).
  • newSingleThreadContext e newFixedThreadPoolContext — para criar pools próprios.


import kotlinx.coroutines.*

fun main() = runBlocking { launch(Dispatchers.Default) { println("Tarefa intensiva em CPU em ${Thread.currentThread().name}") } launch(Dispatchers.IO) { println("Tarefa de E/S em ${Thread.currentThread().name}") }}


Concorrência Estruturada

Uma das principais características do Kotlin é a concorrência estruturada. Ela garante que as coroutines filhas sejam concluídas antes da coroutine pai. Isso evita vazamentos de memória e simplifica o gerenciamento do ciclo de vida.



fun main() = runBlocking {    coroutineScope {        launch {            delay(1000)            println("Tarefa 1 concluída")        }        launch {            delay(500)            println("Tarefa 2 concluída")        }    }    println("Todas as tarefas concluídas")}


2. Canais (Channel) para Transferência de Dados entre Coroutines



Channel é o equivalente a uma fila bloqueante (BlockingQueue), mas para coroutines. Ele permite transferir dados com segurança entre coroutines, suspendendo o remetente se o canal estiver cheio, ou o destinatário se o canal estiver vazio.



Tipos de Canais

  • RendezvousChannel (padrão) — não possui buffer. O envio é bloqueado até o recebimento.
  • BufferedChannel — possui um buffer de tamanho definido.
  • ConflatedChannel — armazena apenas o último valor enviado, sobrescrevendo os anteriores.
  • UnlimitedChannel — buffer ilimitado (cuidado: pode causar OOM).


import kotlinx.coroutines.*import kotlinx.coroutines.channels.*

fun main() = runBlocking { val channel = Channel<Int>(capacity = 5) // Canal com buffer

launch { for (i in 1..10) { channel.send(i) println("Enviado: $i") } channel.close() }

launch { for (value in channel) { println("Recebido: $value") delay(100) } }}


Fan-out e Fan-in

Canais são excelentes para os padrões "fan-out" (um produtor, vários consumidores) e "fan-in" (vários produtores, um consumidor).



3. Flow: Fluxos de Dados Reativos



Ao contrário do Channel, que é "quente" (os dados são enviados independentemente da existência de um assinante), o Flow é um fluxo "frio" que

Blogs

Book Recommendations