---
title: "Dispatcher em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/dispatcher/"
markdown_url: "https://kotlin.dev.br/glossario/dispatcher.MD"
description: "Aprenda o que são Dispatchers em Kotlin Coroutines, como escolher a thread certa para cada tipo de operação."
date: "2025-08-06"
author: "Karina Melo"
---

# Dispatcher em Kotlin: O que É e Como Funciona | Kotlin Brasil

Aprenda o que são Dispatchers em Kotlin Coroutines, como escolher a thread certa para cada tipo de operação.


## O que é Dispatcher em Kotlin?

Um **Dispatcher** em Kotlin Coroutines determina **em qual thread ou pool de threads** uma coroutine sera executada. Ele é o mecanismo que conecta o mundo das coroutines ao mundo das threads do sistema operacional, decidindo onde o código realmente vai rodar.

Escolher o dispatcher correto e fundamental para a performance é o comportamento da aplicação. Uma operação de rede executada no dispatcher errado pode travar a interface do usuário; um calculo pesado no dispatcher errado pode desperdicar recursos.

### Os dispatchers principais

O Kotlin fornece quatro dispatchers padrões através do objeto `Dispatchers`:

```kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    // Dispatcher padrao para trabalho intensivo de CPU
    launch(Dispatchers.Default) {
        println("Default: ${Thread.currentThread().name}")
    }

    // Dispatcher para operacoes de I/O
    launch(Dispatchers.IO) {
        println("IO: ${Thread.currentThread().name}")
    }

    // Dispatcher da thread principal (Android/Swing/JavaFX)
    // launch(Dispatchers.Main) { ... }

    // Dispatcher sem confinamento - nao garante thread especifica
    launch(Dispatchers.Unconfined) {
        println("Unconfined: ${Thread.currentThread().name}")
    }
}
```

### Dispatchers.Default

O `Dispatchers.Default` usa um pool de threads compartilhado com tamanho igual ao número de nucleos da CPU (minimo 2). E otimizado para **trabalho intensivo de CPU**:

```kotlin
suspend fun calcularPrimos(ate: Int): List<Int> = withContext(Dispatchers.Default) {
    (2..ate).filter { numero ->
        (2..Math.sqrt(numero.toDouble()).toInt()).none { numero % it == 0 }
    }
}

fun main() = runBlocking {
    val primos = calcularPrimos(100_000)
    println("Encontrados ${primos.size} primos")
}
```

Use `Dispatchers.Default` para: algoritmos, processamento de dados, serialização/desserializacao, calculos matematicos.

### Dispatchers.IO

O `Dispatchers.IO` usa um pool de threads maior (padrão de 64 threads) projetado para **operações de entrada e saida** que bloqueiam a thread:

```kotlin
suspend fun lerArquivo(caminho: String): String = withContext(Dispatchers.IO) {
    java.io.File(caminho).readText()
}

suspend fun buscarDaApi(url: String): String = withContext(Dispatchers.IO) {
    java.net.URL(url).readText()
}

suspend fun consultarBanco(): List<String> = withContext(Dispatchers.IO) {
    // Simula consulta ao banco
    Thread.sleep(1000)
    listOf("resultado1", "resultado2")
}
```

Use `Dispatchers.IO` para: leitura/escrita de arquivos, chamadas de rede, acesso a banco de dados, chamadas a APIs externas.

### Dispatchers.Main

O `Dispatchers.Main` executa na **thread principal** da aplicação. Em Android, e a thread de UI. Em aplicações desktop com Swing ou JavaFX, e a thread de eventos:

```kotlin
// Android: atualizar UI apos buscar dados
suspend fun carregarEExibir() {
    val dados = withContext(Dispatchers.IO) {
        repositorio.buscarDados()
    }
    // Volta para Main automaticamente
    textView.text = dados.toString()
}
```

Em Android com `viewModelScope` ou `lifecycleScope`, o dispatcher padrão já e `Main`, entao você só precisa mudar explicitamente quando for fazer I/O ou CPU.

### Dispatchers.Unconfined

O `Dispatchers.Unconfined` inicia a coroutine na thread do chamador, mas apos a primeira suspensao, retoma na thread que completou a operação suspensa:

```kotlin
fun main() = runBlocking {
    launch(Dispatchers.Unconfined) {
        println("Antes: ${Thread.currentThread().name}")
        delay(100)
        println("Depois: ${Thread.currentThread().name}") // Pode ser outra thread!
    }
}
```

Use com extrema cautela. O `Unconfined` e útil em testes e casos muito específicos, mas pode causar comportamento imprevisivel em código de producao.

### withContext: trocando de dispatcher

A função `withContext` troca o dispatcher dentro de uma coroutine sem criar uma nova:

```kotlin
suspend fun processarDados(): String {
    // Busca dados em IO
    val dadosBrutos = withContext(Dispatchers.IO) {
        repositorio.buscarDados()
    }

    // Processa em Default
    val dadosProcessados = withContext(Dispatchers.Default) {
        dadosBrutos.map { transformar(it) }
    }

    return dadosProcessados.joinToString()
}
```

`withContext` e mais eficiente que `launch` + `join` porque não cria uma nova coroutine; apenas muda o contexto de execução.

### Criando dispatchers customizados

Para cenários específicos, você pode criar seus próprios dispatchers:

```kotlin
// Dispatcher com thread unica (util para acesso sequencial)
val dispatcherDeBanco = newSingleThreadContext("BancoDeDados")

// Dispatcher com pool fixo
val dispatcherDeProcessamento = newFixedThreadPoolContext(4, "Processamento")

// Converter um Executor em dispatcher
val meuExecutor = java.util.concurrent.Executors.newCachedThreadPool()
val dispatcherCustom = meuExecutor.asCoroutineDispatcher()
```

Lembre-se de fechar dispatchers customizados quando não forem mais necessários para evitar vazamento de threads:

```kotlin
dispatcherDeBanco.close()
dispatcherDeProcessamento.close()
```

### limitedParallelism

A partir do Kotlin 1.6, você pode criar uma visao limitada de um dispatcher existente:

```kotlin
// Limita IO a no maximo 4 threads para uma operacao especifica
val dispatcherLimitado = Dispatchers.IO.limitedParallelism(4)

suspend fun processarArquivos(arquivos: List<String>) = coroutineScope {
    arquivos.map { arquivo ->
        async(dispatcherLimitado) {
            lerEProcessar(arquivo)
        }
    }.awaitAll()
}
```

Isso e útil para evitar que uma operação consuma todas as threads do pool de I/O, deixando outras operações sem recursos.

### Quando usar cada dispatcher

| Dispatcher | Uso | Exemplos |
|---|---|---|
| Default | CPU intensivo | Calculos, parsing, serialização |
| IO | Bloqueio de I/O | Rede, arquivos, banco de dados |
| Main | UI | Atualizar tela, mostrar dialogo |
| Unconfined | Testes | Testes unitarios simples |

### Casos de Uso no Mundo Real

1. **aplicações Android com chamadas de API**: em apps Android, o padrão mais comum e usar `Dispatchers.IO` para chamadas de rede e banco de dados, e `Dispatchers.Main` para atualizar a interface do usuário com os resultados. ViewModels tipicamente lancam coroutines no `Main` e trocam para `IO` com `withContext` quando necessário.

2. **Servidores backend com Ktor ou Spring**: em aplicações server-side, `Dispatchers.IO` e usado para operações de banco de dados e chamadas a servicos externos, enquanto `Dispatchers.Default` processa lógica de negócio intensiva como geracao de relatorios, compressao de dados ou transformacoes em lote.

3. **Processamento de imagens e arquivos**: aplicações que manipulam imagens ou processam grandes volumes de arquivos usam `Dispatchers.Default` para operações de CPU (redimensionamento, compressao) e `Dispatchers.IO` para leitura e escrita no disco, frequentemente combinados com `limitedParallelism` para controlar o uso de recursos.

4. **Pipelines de dados em tempo real**: sistemas que consomem dados de sensores, WebSockets ou filas de mensagens utilizam dispatchers customizados com `newSingleThreadContext` para garantir processamento sequencial e thread-safe, combinados com `Dispatchers.Default` para etapas de transformacao paralela.

### Boas Praticas

- Use `withContext` em vez de `launch` quando precisar apenas trocar de dispatcher e aguardar o resultado. Isso evita a criação desnecessaria de uma nova coroutine e mantém o fluxo sequencial.
- Encapsule a escolha do dispatcher dentro de funções suspend de repositórios e data sources, em vez de exigir que o chamador saiba qual dispatcher usar. Isso segue o princípio de responsabilidade única.
- Utilize `limitedParallelism` para controlar o grau de concorrencia em operações que acessam recursos limitados, como conexoes de banco de dados ou APIs com rate limiting.
- Evite `Dispatchers.Unconfined` em código de producao. Ele e útil para testes unitarios simples, mas em producao pode causar comportamento imprevisivel ao retomar a coroutine em threads inesperadas.
- Injete dispatchers como dependência em classes que os utilizam, permitindo que testes substituam por `TestDispatcher` para execução deterministica e controlada.

### Perguntas Frequentes

**P: Qual a diferenca entre Dispatchers.Default e Dispatchers.IO?**
R: O `Dispatchers.Default` usa um pool de threads limitado ao número de nucleos da CPU e e otimizado para trabalho computacional intensivo. O `Dispatchers.IO` usa um pool maior (até 64 threads por padrão) e e projetado para operações que bloqueiam a thread, como leitura de arquivos ou chamadas de rede. Usar o dispatcher errado pode causar problemas de performance: CPU intensivo no IO desperdiça context switching, e I/O bloqueante no Default pode esgotar os poucos threads disponiveis.

**P: Preciso sempre especificar um dispatcher ao lancar uma coroutine?**
R: Nao. Se você não especificar, a coroutine herda o dispatcher do escopo pai. Em Android com `viewModelScope`, o dispatcher padrão e `Dispatchers.Main`. Em `runBlocking`, e o dispatcher da thread que chamou. Especifique um dispatcher apenas quando precisar de comportamento diferente do herdado.

**P: Como escolher entre criar um dispatcher customizado e usar limitedParallelism?**
R: Prefira `limitedParallelism` na maioria dos casos, pois ele reutiliza threads do pool existente sem criar threads extras. Crie dispatchers customizados apenas quando precisar de isolamento total de threads, como em operações que exigem thread-local storage ou acesso a bibliotecas nativas que não sao thread-safe.

**P: E seguro compartilhar o mesmo dispatcher entre diferentes partes da aplicação?**
R: Sim, os dispatchers padrão (`Default`, `IO`, `Main`) sao projetados para uso compartilhado global. Para dispatchers customizados, o compartilhamento e seguro desde que você gerencie o ciclo de vida corretamente e feche o dispatcher quando a aplicação não precisar mais dele.

### Erros comuns

1. **Fazer I/O no Dispatchers.Default**: operações que bloqueiam a thread desperdicam os poucos threads do pool Default. Use IO para operações bloqueantes.

2. **Atualizar UI fora do Dispatchers.Main**: em Android, acessar Views fora da main thread causa crash. Sempre volte para Main antes de atualizar a UI.

3. **Usar Dispatchers.IO para CPU**: IO tem muitas threads, o que é desperdicio para trabalho de CPU. O excesso de context switching reduz a performance.

4. **Criar dispatchers customizados sem necessidade**: os dispatchers padrões atendem a grande maioria dos casos. Crie customizados apenas quando tiver necessidades específicas de controle.

5. **Nao fechar dispatchers customizados**: dispatchers criados com `newSingleThreadContext` ou `newFixedThreadPoolContext` precisam ser fechados para liberar threads.

6. **Confundir withContext com launch**: `withContext` suspende e retorna um resultado; `launch` cria uma coroutine que roda em paralelo. Use `withContext` para trocar de dispatcher e continuar sequencialmente.

### Termos relacionados

- **Coroutine**: unidade de execução leve que roda em um dispatcher específico.
- **CoroutineContext**: contexto que inclui o dispatcher, o Job e outros elementos.
- **withContext**: função que muda o dispatcher dentro de uma coroutine.
- **launch/async**: funções que criam novas coroutines, opcionalmente com um dispatcher específico.
- **Job**: elemento do contexto que representa o ciclo de vida da coroutine.
- **Flow**: streams reativos que podem mudar de dispatcher com `flowOn`.

Dispatchers são o elo entre coroutines e threads. Entender quando e como usa-los e essencial para escrever código concorrente que seja eficiente e livre de bugs de threading.
