---
title: "Coroutine em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/coroutine/"
markdown_url: "https://kotlin.dev.br/glossario/coroutine.MD"
description: "Descubra o que são Coroutines em Kotlin, como funcionam e por que são a forma moderna de lidar com código assíncrono."
date: "2026-02-05"
author: "Karina Melo"
---

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

Descubra o que são Coroutines em Kotlin, como funcionam e por que são a forma moderna de lidar com código assíncrono.


## O que é Coroutine em Kotlin?

Coroutines são o mecanismo do Kotlin para lidar com **programação assíncrona** de forma simples e eficiente. Em vez de usar callbacks aninhados ou threads pesadas, você escreve código assíncrono que parece sequencial -- fácil de ler, fácil de manter.

Pense nas coroutines como "threads leves". Você pode rodar milhares delas sem estourar a memória, porque elas não criam threads do sistema operacional -- são gerenciadas pelo próprio Kotlin. O conceito é similar às goroutines de [Go](https://golang.com.br/) e ao async/await de [Rust](https://rustlang.com.br/), cada linguagem com sua abordagem para concorrência leve.

Uma analogia útil: imagine um restaurante. Threads tradicionais seriam como ter um garçom exclusivo para cada mesa -- caro e limitado. Coroutines funcionam como um garçom eficiente que atende várias mesas: enquanto espera o pedido de uma mesa ser preparado na cozinha, ele vai atender outra. O garçom (thread) nunca fica parado, é o restaurante funciona com poucos garçons atendendo muitas mesas.

### Por que usar coroutines?

O problema clássico de código assíncrono é o tal do "callback hell". Coroutines resolvem isso permitindo que você escreva código que parece síncrono, mas executa de forma assíncrona por baixo dos panos.

### Exemplo básico

```kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    println("Início")

    launch {
        delay(1000)
        println("Coroutine finalizada!")
    }

    println("Fazendo outras coisas...")
    delay(1500)
    println("Fim")
}
```

Saída:
```
Início
Fazendo outras coisas...
Coroutine finalizada!
Fim
```

O [launch](/glossario/launch/) cria uma nova coroutine, e o `delay` suspende a execução sem bloquear a thread. Enquanto uma coroutine está esperando, outras podem rodar tranquilamente.

### Conceitos fundamentais

- **CoroutineScope**: define o ciclo de vida das coroutines
- **[launch](/glossario/launch/)**: inicia uma coroutine que não retorna valor
- **[async](/glossario/async/)**: inicia uma coroutine que retorna um resultado
- **[suspend](/glossario/suspend/)**: marca uma função que pode ser suspensa
- **[Dispatchers](/glossario/dispatcher/)**: controlam em qual thread a coroutine vai rodar

### Exemplo com chamada de rede simulada

```kotlin
import kotlinx.coroutines.*

suspend fun buscarDados(): String {
    delay(2000) // Simula uma chamada de rede
    return "Dados carregados com sucesso"
}

fun main() = runBlocking {
    println("Buscando dados...")
    val resultado = buscarDados()
    println(resultado)
}
```

### Quando usar?

Coroutines são essenciais para operações de I/O (chamadas de rede, banco de dados, leitura de arquivos), processamento em background e qualquer tarefa que não deveria travar a interface do usuário. No Android, são praticamente obrigatórias hoje em dia.

### Chamadas paralelas com async e await

Quando você precisa fazer várias operações ao mesmo tempo e combinar os resultados, [async](/glossario/async/) é a escolha certa:

```kotlin
import kotlinx.coroutines.*

suspend fun buscarUsuario(): String {
    delay(1000)
    return "Karina"
}

suspend fun buscarPedidos(): List<String> {
    delay(1200)
    return listOf("Pedido #1", "Pedido #2", "Pedido #3")
}

fun main() = runBlocking {
    val inicio = System.currentTimeMillis()

    val usuario = async { buscarUsuario() }
    val pedidos = async { buscarPedidos() }

    println("Usuário: ${usuario.await()}")
    println("Pedidos: ${pedidos.await()}")

    val tempo = System.currentTimeMillis() - inicio
    println("Tempo total: ${tempo}ms") // ~1200ms, nao ~2200ms
}
```

As duas chamadas rodam em paralelo, e o tempo total é o da chamada mais lenta, não a soma das duas.

### Tratamento de erros com coroutines

Lidar com exceções em coroutines exige atenção ao [scope](/glossario/scope/) e ao [job](/glossario/job/):

```kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, excecao ->
        println("Erro capturado: ${excecao.message}")
    }

    val scope = CoroutineScope(Dispatchers.Default + handler)

    scope.launch {
        println("Iniciando operacao...")
        delay(500)
        throw RuntimeException("Falha na conexão")
    }

    delay(1000) // Aguarda para ver o resultado
    // Saída: Erro capturado: Falha na conexão
}
```

### Coroutines com Flow para dados em sequência

Para fluxos de dados contínuos, combine coroutines com [Flow](/glossario/flow/):

```kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun monitorarTemperatura(): Flow<Double> = flow {
    val sensores = listOf(22.5, 23.1, 24.0, 23.8, 25.2)
    for (temp in sensores) {
        delay(500) // Simula leitura do sensor
        emit(temp)
    }
}

fun main() = runBlocking {
    monitorarTemperatura()
        .filter { it > 23.0 }
        .collect { temperatura ->
            println("Alerta: temperatura em ${temperatura} graus")
        }
}
```

### Casos de Uso no Mundo Real

- **Chamadas de API em Android**: usar `viewModelScope.launch` para buscar dados de APIs REST sem travar a UI, substituindo AsyncTask e RxJava.
- **Processamento de arquivos**: ler e processar arquivos grandes linha por linha usando coroutines com [Dispatchers.IO](/glossario/dispatcher/) para não bloquear a thread principal.
- **Websockets e streaming**: manter conexões ativas com servidores usando [Flow](/glossario/flow/) e [Channel](/glossario/channel/) para receber dados em tempo real.
- **Operações em banco de dados**: executar consultas Room ou Exposed em coroutines para manter a responsividade da aplicação.
- **Tarefas periódicas**: usar `while(isActive)` com `delay` para executar verificações periódicas sem criar timers tradicionais.

### Boas Práticas

- **Nunca use `runBlocking` em código de produção** (exceto em `main()` ou testes). Ele bloqueia a thread, anulando o propósito das coroutines.
- **Sempre defina um [Dispatcher](/glossario/dispatcher/) adequado**: use `Dispatchers.IO` para operações de I/O, `Dispatchers.Default` para CPU intensiva e `Dispatchers.Main` para atualizações de UI.
- **Respeite a estrutura de concorrência (structured concurrency)**: lance coroutines dentro de um [scope](/glossario/scope/) adequado para que sejam canceladas automaticamente quando o scope é destruído.
- **Use `withContext` para trocar de dispatcher** em vez de lançar uma nova coroutine.
- **Prefira [Flow](/glossario/flow/) sobre [Channel](/glossario/channel/)** para fluxos de dados frios (que só produzem quando alguém consome).

### Erros Comuns

- **Esquecer de tratar exceções**: exceções em `launch` propagam e cancelam o scope pai. Use `try-catch` dentro da coroutine ou um `CoroutineExceptionHandler`.
- **Usar `GlobalScope` indiscriminadamente**: coroutines lançadas em `GlobalScope` não respeitam ciclo de vida e podem causar vazamento de memória. Use scopes vinculados ao componente (como `viewModelScope` no Android).
- **Chamar funções [suspend](/glossario/suspend/) sem estar em uma coroutine**: funções suspend só podem ser chamadas de dentro de outra função suspend ou de um builder como `launch` ou `async`.
- **Não cancelar coroutines desnecessárias**: se o usuário saiu de uma tela, as coroutines daquela tela devem ser canceladas. Usar scopes vinculados ao ciclo de vida resolve isso automaticamente.

### Perguntas Frequentes

**Qual a diferença entre `launch` e `async`?**
[launch](/glossario/launch/) inicia uma coroutine que não retorna resultado (retorna um `Job`). [async](/glossario/async/) inicia uma coroutine que retorna um resultado encapsulado em um `Deferred`, acessível via `await()`.

**Coroutines substituem threads?**
Não completamente. Coroutines rodam sobre threads, mas permitem multiplexar muitas tarefas em poucas threads. Para tarefas CPU-bound pesadas, você ainda precisa de threads adequadas via `Dispatchers.Default`.

**Posso usar coroutines em projetos backend?**
Sim. Frameworks como Ktor são construídos sobre coroutines. Spring Boot também oferece suporte completo a coroutines com `suspend` functions em controllers.

**O que acontece se uma coroutine dentro de `async` lançar uma exceção?**
A exceção é encapsulada no `Deferred` e será relançada quando você chamar `await()`. Use `try-catch` ao redor do `await()` ou um [SupervisorScope](/glossario/supervisor/) para evitar que o erro cancele as coroutines irmãs.
