Dispatchers — conceitos-chave, tipos de dispatchers e como funcionam

Autor: IT Sectr Publicado: 2026-06-22 Tempo de leitura: 9 min

Dispatchers em Kotlin Coroutines são componentes de CoroutineContext que determinam as threads para execução de corrotinas: Main (thread da UI), IO (rede e disco), Default (tarefas intensivas de CPU) e Unconfined (thread atual). Cada dispatcher gerencia um pool de threads especializado otimizado para um tipo específico de trabalho. De acordo com o guia da JetBrains, 2024, escolher o dispatcher certo é crítico para o desempenho e a estabilidade da aplicação.

Pontos Principais

  • Dispatchers — dispatchers de corrotinas predefinidos que gerenciam a distribuição de tarefas entre threads
  • Dispatchers.Main — thread da UI do Android, para atualizar a interface e trabalhar com View
  • Dispatchers.IO — pool para requisições de rede, leitura/escrita de arquivos e BD (até 64 threads)
  • Dispatchers.Default — pool para tarefas intensivas de CPU com base no número de núcleos do processador
  • Dispatchers.Unconfined — herda a thread atual, sem alternância

O que são Dispatchers?

Dispatchers são implementações da interface CoroutineDispatcher, que são elementos de CoroutineContext. Eles determinam em qual thread ou pool de threads a corrotina será executada. Ao criar uma corrotina via launch ou async, o dispatcher pode ser passado como primeiro parâmetro: launch(Dispatchers.IO) { ... }. Se nenhum dispatcher for especificado, ele é herdado do CoroutineScope externo.

Kotlin fornece quatro dispatchers integrados: Main, IO, Default, Unconfined. Cada dispatcher usa seu próprio pool de threads otimizado para um tipo específico de operação. Escolher o dispatcher certo determina o desempenho da aplicação: uma escolha errada leva a lentidão na UI, núcleos de CPU ociosos ou uso ineficiente de threads.

DispatcherPool de ThreadsMáx. de ThreadsUso
Dispatchers.MainUm (UI)1Atualizações de UI, LiveData, View
Dispatchers.IOPool IO64 (limitedParallelism)Rede, arquivos, BD
Dispatchers.DefaultPool CPUN núcleosOrdenação, análise, cálculos
Dispatchers.UnconfinedThread atualN/AOperações intermediárias, testes

Dispatchers.Main: Thread da UI

Dispatchers.Main é o dispatcher que executa corrotinas na thread principal do Android. Ele é projetado para operações relacionadas à interface: atualizar TextView, chamar notifyDataSetChanged, trabalhar com LiveData e StateFlow. No Android, este dispatcher é implementado via Handler (Looper.getMainLooper()).

kotlin
// Correct switch to Main for UI updates
viewModelScope.launch(Dispatchers.IO) {
    val data = repository.fetchData()
    withContext(Dispatchers.Main) {
        _uiState.value = data
    }
}

Se uma corrotina já está no dispatcher Main, um withContext(Dispatchers.Main) adicional não cria sobrecarga — o dispatcher verifica a thread atual e pula a alternância. withContext é a forma preferida de alternar entre dispatchers.

Dispatchers.IO: Operações de Rede e Disco

Dispatchers.IO é um dispatcher otimizado para operações de E/S: requisições HTTP (Ktor, OkHttp), leitura e escrita de arquivos, trabalho com Room ou SQLDelight. Ele usa um pool de 64 threads por padrão, escalável sob carga. Cada nova requisição de E/S pode criar uma thread adicional até atingir o limite.

Limitação de Paralelismo

Para controlar o número de operações de E/S simultâneas, use limitedParallelism(). Esta função cria um novo dispatcher com um limite no número de threads paralelas, evitando o esgotamento do pool durante operações em massa.

kotlin
val limitedIo = Dispatchers.IO.limitedParallelism(4)

// Load 100 files with limit of 4 concurrent operations
coroutineScope {
    val files = (1..100).map { index ->
        async(limitedIo) {
            downloadFile("file_$index")
        }
    }
    files.awaitAll()
}

Use o dispatcher IO para todas as operações onde a corrotina passa tempo esperando (I/O-bound). Tarefas intensivas de CPU no dispatcher IO são ineficientes — elas ocupam threads destinadas a E/S, reduzindo a vazão do sistema.

Dispatchers.Default: Tarefas Intensivas de CPU

Dispatchers.Default é o dispatcher para operações computacionais que carregam o processador: ordenação, filtragem, análise JSON (Moshi, Kotlinx Serialization), processamento de imagens, cálculos. O tamanho do pool é igual ao número de núcleos do processador (mas não menos que 2). Isso garante a máxima utilização da CPU sem alternância de contexto.

kotlin
suspend fun processData(input: List<RawRecord>): List<ProcessedRecord> {
    return withContext(Dispatchers.Default) {
        input
            .parallelStream()
            .map { transform(it) }
            .toList()
    }
}

Não use Dispatchers.Default para operações de E/S — isso bloqueará threads do pool de CPU que poderiam estar processando tarefas computacionais. A separação de IO e Default permite a utilização ideal dos recursos do sistema: threads IO aguardam E/S, threads CPU estão constantemente ocupadas com cálculos.

Dispatchers.Unconfined: Thread Atual

Dispatchers.Unconfined é um dispatcher especial que não vincula uma corrotina a nenhum pool. A corrotina começa a execução na thread onde launch/async foi chamado, e após a suspensão retoma na thread que chamou resume. Este comportamento é adequado para operações intermediárias que não requerem um contexto fixo.

kotlin
fun main() = runBlocking {
    launch(Dispatchers.Unconfined) {
        println("Before delay: ${Thread.currentThread().getName()}")
        delay(500L)
        println("After delay: ${Thread.currentThread().getName()}")
    }
}

Em código de produção, Dispatchers.Unconfined é raramente usado. Principais casos de uso: transformações leves antes de passar dados para outro dispatcher e testes. Para cargas de produção, use dispatchers explícitos — Unconfined é imprevisível porque a thread de execução depende da implementação do resume.

Como Escolher um Dispatcher

A seleção do dispatcher depende do tipo de tarefa: operações de UI → Main, I/O-bound → IO, CPU-bound → Default, intermediárias → herdar do escopo. Para Android, recomenda-se lançar uma corrotina no dispatcher onde o trabalho principal é realizado e alternar para Main via withContext antes de atualizar a UI.

  • Não execute operações de E/S no dispatcher Main — isso bloqueia a UI
  • Não execute tarefas intensivas de CPU no dispatcher IO — isso consome ineficientemente as threads do pool IO
  • Use limitedParallelism para controlar a concorrência durante operações de E/S em massa
  • Alterne o dispatcher usando withContext, não criando um novo escopo
  • Herde o dispatcher do escopo se a corrotina não exigir um pool específico

Para cenários complexos, combine dispatchers usando o operador +: Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler. Isso cria um CoroutineContext com um dispatcher especificado, tratamento de erros e uma hierarquia de Job isolada.

Perguntas Frequentes

Qual a diferença entre Dispatchers.IO e Dispatchers.Default?

Dispatchers.IO usa um pool de até 64 threads para operações I/O-bound (espera de E/S), enquanto Dispatchers.Default usa um pool baseado no número de núcleos de CPU para tarefas computacionais. Quando as threads são escassas, ambos os pools podem compartilhar threads entre si.

Posso criar meu próprio dispatcher em Kotlin Coroutines?

Sim, use newSingleThreadContext() para uma thread única ou newFixedThreadPoolContext() para um pool fixo. Para produção, use limitedParallelism() baseado em dispatchers existentes — isso é mais eficiente do que criar novos pools.

O que acontece quando Dispatchers.Main é chamado de uma thread em segundo plano?

Se Dispatchers.Main não estiver disponível (por exemplo, em um teste JUnit ou serviço em segundo plano), uma IllegalStateException é lançada. Use TestCoroutineDispatcher para testes e Dispatchers.IO ou Default para serviços em segundo plano.

Como limitar o número de operações de E/S paralelas?

Use Dispatchers.IO.limitedParallelism(N), onde N é o número máximo de threads paralelas. Isso evita o esgotamento do pool durante requisições em massa e fornece paralelismo controlado.

Quando usar Dispatchers.Unconfined?

Dispatchers.Unconfined é adequado para operações intermediárias: transformações leves de dados antes de passar para outro dispatcher, cenários de teste. Em código de produção Android, não é recomendado devido à thread de execução indefinida após a suspensão.

Resumo

  • Dispatchers — componentes de CoroutineContext que determinam as threads de execução das corrotinas
  • Dispatchers.Main — para operações de UI no Android, uma thread principal
  • Dispatchers.IO — para operações de rede e disco, pool de até 64 threads
  • Dispatchers.Default — para cálculos intensivos de CPU, pool baseado no número de núcleos
  • Dispatchers.Unconfined — sem vinculação de thread, para operações intermediárias
  • withContext — o mecanismo principal para alternar entre dispatchers dentro de uma corrotina
  • Escolher o dispatcher errado leva a lentidão na UI ou uso ineficiente de recursos

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também