Coroutines — conceitos-chave, Job e Dispatchers em Kotlin

Autor: IT Sectr Publicado: 2026-03-16 Tempo de leitura: 8 min

Coroutines (corrotinas) são threads leves do Kotlin para programação assíncrona, disponíveis através da biblioteca kotlinx.coroutines. De acordo com JetBrains Kotlin Documentation, 2026, Coroutines permitem suspender a execução de uma função sem bloquear uma thread, ao contrário das Threads tradicionais. As corrotinas são executadas em um pool limitado de threads, tornando-as mil vezes mais leves que threads nativas. Kotlin Coroutines são totalmente integradas com Android Jetpack, Retrofit, Room e outras bibliotecas populares do ecossistema Android.

Pontos Principais

  • Coroutines — threads leves Kotlin para código assíncrono sem bloqueio
  • Função suspend — uma função que pode pausar e retomar sem bloquear uma thread
  • Dispatcher determina o pool de threads para execução da corrotina
  • Job — um descritor de corrotina com suporte a cancelamento e rastreamento de estado
  • CoroutineScope gerencia o ciclo de vida das corrotinas e seu cancelamento ao finalizar

O que são corrotinas Kotlin

Coroutines são um mecanismo de programação assíncrona em Kotlin, implementado na biblioteca kotlinx.coroutines. Ao contrário das threads do sistema operacional, as corrotinas não estão vinculadas a uma thread específica: podem suspender em uma thread e retomar em outra. Uma única thread pode executar milhares de corrotinas, alternando entre elas com sobrecarga mínima.

As corrotinas apareceram no Kotlin 1.3 (2018) como um recurso experimental e tornaram-se estáveis no Kotlin 1.5 (2021). Coroutines resolvem o problema de callback hell de forma semelhante ao async/await, mas fornecem uma API mais rica: canais (Channel), Flow, tratamento de exceções na hierarquia Job e integração direta com Android Lifecycle.

Segundo a JetBrains (2025), cada corrotina consome cerca de 100 bytes de memória contra 1+ MB de uma thread nativa. Isso permite executar milhões de corrotinas em uma única aplicação sem risco de OutOfMemoryError. É a leveza das corrotinas que as torna a ferramenta preferida para assincronia no Android.

Como as corrotinas funcionam internamente

Cada corrotina Kotlin é compilada em uma máquina de estados usando Continuation Passing Style (CPS). O compilador adiciona um parâmetro Continuation oculto a cada função suspend. O Continuation contém o ponto de retomada e todas as variáveis locais. Quando uma corrotina suspende, o runtime salva o Continuation e, quando retoma, restaura-o em qualquer thread disponível do pool do Dispatcher.

Funções suspend: pausa e retomada

suspend é uma palavra-chave do Kotlin que marca uma função como suspensível. Tal função só pode ser chamada de outra função suspend ou de uma corrotina. Dentro de uma função suspend, você pode chamar outras funções suspend em qualquer ordem, e cada ponto de chamada é um ponto potencial de suspensão.

A mecânica é simples: quando uma função suspend chama outra função suspend, ela suspende nesse ponto, liberando a thread. Após a função chamada ser concluída, o runtime continua a execução a partir do local salvo. Isso é chamado de cooperative cancellation — nenhuma thread é bloqueada.

  • Suspensão — a corrotina libera a thread sem bloqueá-la
  • Retomada — a corrotina continua de onde suspendeu
  • Thread — uma corrotina pode suspender na thread A e retomar na thread B
  • Exceções — tratadas via try/catch como em código síncrono

Importante: uma função suspend não é assíncrona por padrão. A ordem de execução permanece sequencial se launch ou async não forem usados. suspend apenas permite que a função seja pausada sem bloquear a thread e faça parte do contexto de corrotina. Continuation Passing Style é um modelo de compilação onde cada função suspend recebe um callback Continuation oculto, e o compilador gera uma máquina de estados para gerenciar suspensões e retomadas.

CoroutineScope e Concorrência Estruturada

CoroutineScope é um contexto que define o ciclo de vida das corrotinas. Todas as corrotinas devem ser lançadas dentro de um escopo. Quando um escopo é cancelado (por exemplo, quando uma Activity termina), todas as suas corrotinas filhas são automaticamente canceladas. Isso evita vazamentos de tarefas em segundo plano. Android Jetpack fornece escopos prontos para cada componente: viewModelScope para ViewModel e lifecycleScope para Activity e Fragment, que são automaticamente cancelados quando o componente correspondente é destruído.

Concorrência Estruturada (Structured Concurrency) é um princípio que garante que uma corrotina não será concluída até que todas as suas corrotinas filhas tenham sido concluídas. A hierarquia Job forma uma árvore: uma corrotina raiz cria um parent job, os filhos criam child jobs. Cancelar um parent job propaga-se para todos os filhos. Structured Concurrency é uma diferença fundamental entre corrotinas e threads.

ScopeOnde é usadoCancelamento
GlobalScopeApenas para tarefas daemonNão é cancelado automaticamente
viewModelScopeAndroid ViewModelAo limpar o ViewModel
lifecycleScopeAndroid Activity/FragmentAo destruir o lifecycle
coroutineScopeDentro de função suspendAo cancelar o job pai

SupervisorJob para tratamento de erros

Um Job normal cancela todos os siblings quando uma corrotina filha falha. SupervisorJob é uma exceção: uma falha em uma corrotina filha não afeta as outras. Isso é importante quando várias tarefas independentes são executadas em paralelo e uma delas pode falhar sem precisar cancelar as outras.

Dispatchers e construtores de corrotinas

Dispatchers determinam em quais threads as corrotinas são executadas. Dispatchers.Main — a thread principal da UI Android. Dispatchers.IO — um pool para operações de bloqueio (rede, disco). Dispatchers.Default — para tarefas intensivas em CPU. Dispatchers.Unconfined — inicia na thread atual mas não garante permanecer nela. Escolher o Dispatcher correto é crítico para o desempenho: uma tarefa IO no Default bloqueará o pool de computação, enquanto uma tarefa de CPU no IO criará threads desnecessárias.

withContext — uma função para alternar o Dispatcher dentro de uma corrotina. Por exemplo, uma função suspend que analisa JSON pode alternar para Dispatchers.Default para computação e retornar ao Dispatchers.Main para atualizar a UI. withContext é o construtor mais usado no desenvolvimento Android.

Três principais construtores de corrotinas

launch — inicia uma corrotina, retorna um Job, não retorna resultado (fire-and-forget). async — inicia uma corrotina, retorna um Deferred do qual o resultado pode ser obtido via await. runBlocking — bloqueia a thread atual para executar uma corrotina (apenas para testes e funções main). Escolha do construtor depende do cenário: launch é adequado para eventos e atualizações, async para tarefas com resultado, runBlocking apenas para testes ou pontos de entrada.

Exemplos de código com corrotinas em Kotlin

Vamos considerar três cenários práticos: uma corrotina básica com launch, uma chamada paralela com async e tratamento de erros com SupervisorJob.

Iniciar uma corrotina com launch

viewModelScope.launch inicia uma corrotina no contexto do ViewModel. Quando o ViewModel é limpo, a corrotina é automaticamente cancelada.

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

Requisições paralelas com async

coroutineScope com async inicia três requisições em paralelo. Os resultados são coletados via .await(). Se alguma requisição falhar, todas são canceladas.

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

Tratamento de erros com SupervisorJob

SupervisorJob permite que cada corrotina termine independentemente. Um erro em uma requisição não cancela as outras.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

Corrotinas vs threads: comparação e cenários

Threads são um primitivo do sistema operacional. Cada thread tem sua própria pilha (~1 MB) e requer uma chamada de sistema para criação e alternância. Corrotinas são um primitivo da linguagem, não vinculado ao SO. Elas usam Continuation para salvar o estado e alternam no nível do runtime sem chamadas de sistema.

  • Memória — thread ~1 MB, corrotina ~100 bytes. Uma diferença de 10.000 vezes
  • Criação — thread ~1 µs syscall, corrotina ~0,01 µs no nível JVM
  • Alternância — thread ~0,1 µs (syscall), corrotina ~0,001 µs (continuation)
  • Máximo — milhares de threads vs milhões de corrotinas por dispositivo
  • Cancelamento — uma thread não pode ser cancelada externamente (Thread.stop obsoleto), uma corrotina pode via Job.cancel()

Segundo o Google (2025), usar corrotinas em vez de threads reduz o consumo de memória para tarefas em segundo plano em aplicativos Android em 90–95%. Todas as bibliotecas modernas do Android (Retrofit, Room, WorkManager) têm suporte integrado a corrotinas através de funções suspend. Ktor (framework cliente HTTP da JetBrains) também é construído inteiramente sobre corrotinas, fornecendo funções suspend para cada requisição sem API de callbacks. Room suporta corrotinas através de funções suspend no DAO, permitindo executar consultas ao banco de dados sem bloquear a thread principal.

Quando usar threads em vez de corrotinas

As threads permanecem necessárias para código nativo via JNI, chamadas bloqueantes de CPU-intensive sem limite de tempo (renderização de vídeo, simulações) e ao integrar com bibliotecas C. Para todo o resto — corrotinas.

Perguntas Frequentes

Como uma corrotina difere de uma thread?

Corrotina é uma unidade de trabalho suspensível executada em uma thread existente. Uma thread é um recurso do sistema com sua própria pilha. Corrotinas são milhares de vezes mais leves que threads e não bloqueiam recursos ao suspender.

O que é Dispatchers.IO e como difere do Default?

Dispatchers.IO é projetado para operações de E/S bloqueantes (rede, arquivos) e pode criar novas threads quando necessário. Dispatchers.Default tem um pool de tamanho fixo (número de núcleos de CPU) para computações intensivas em CPU.

Como cancelar uma corrotina em execução?

Job.cancel() cancela a corrotina e todos os seus filhos. Para verificar o cancelamento dentro de uma corrotina, use ensureActive() — ele lança uma CancellationException se a corrotina estiver cancelada.

Corrotinas podem ser usadas com RxJava?

Sim — através da biblioteca kotlinx-coroutines-rx3. Ela fornece funções awaitSingle, awaitFirst e outras para converter Observable/Single em funções suspend e vice-versa através de flowable.

O que é Flow em corrotinas?

Flow é um fluxo de dados assíncrono a frio, o equivalente em corrotinas do RxJava Observable. Flow emite valores sequencialmente e completa com uma exceção ou sucesso. Suporta map, filter, catch e outros operadores.

Resumo

  • Coroutines — threads leves Kotlin com suspensão sem bloqueio via Continuation Passing Style
  • suspend — a palavra-chave para marcar funções suspensíveis
  • Dispatchers gerenciam o pool de threads: Main, IO, Default respectivamente
  • CoroutineScope vincula o ciclo de vida das corrotinas a um componente (Activity, ViewModel)
  • launch inicia uma corrotina sem resultado, async/await — com resultado
  • Structured Concurrency garante o cancelamento hierárquico das corrotinas filhas
  • Corrotinas vs threads — corrotinas são 10.000 vezes mais leves e são o padrão para Android

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