Kotlin Academy · Aula

Atores e gerenciamento estruturado de estado

Use padrões no estilo de atores para serializar o acesso ao estado em código concorrente.

Aula 4 de 413 etapas

Atores e gerenciamento estruturado de estado é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.

O que é um ator?

Um ator é uma corrotina que possui um estado mutável privado e se comunica por meio de um canal. O código externo nunca acessa o estado diretamente — apenas por meio de mensagens.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
sealed class CounterMsg
object Increment : CounterMsg()
class GetCount(val response: CompletableDeferred<Int>) : CounterMsg()
fun CoroutineScope.counterActor() = actor<CounterMsg> {
    var counter = 0
    for (msg in channel) {
        when (msg) {
            is Increment -> counter++
            is GetCount  -> msg.response.complete(counter)
        }
    }
}

Usando o ator

Envie mensagens ao ator usando send. O ator as processa uma de cada vez, serializando o acesso ao estado.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
// (CounterMsg sealed class from previous scene)
fun main() = runBlocking {
    val counter = counterActor()
    repeat(100) { counter.send(Increment) }
    val response = CompletableDeferred<Int>()
    counter.send(GetCount(response))
    println("Count: ${response.await()}") // 100
    counter.close()
}

O ator substitui o mutex

Os atores eliminam a necessidade de mutexes ao tornar o acesso ao estado sequencial por definição. Todas as mutações acontecem dentro de uma única corrotina.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
sealed class Msg
object Inc : Msg()
data class Get(val d: CompletableDeferred<Int>) : Msg()
fun CoroutineScope.safeCounter() = actor<Msg> {
    var n = 0
    for (m in channel) when(m) {
        is Inc -> n++
        is Get -> m.d.complete(n)
    }
}
fun main() = runBlocking {
    val a = safeCounter()
    repeat(1000) { a.send(Inc) }
    val d = CompletableDeferred<Int>()
    a.send(Get(d))
    println(d.await()) // 1000
    a.close()
}

Protocolo de mensagens tipado

Defina seu protocolo de mensagens como uma hierarquia de classes seladas para obter tratamento exaustivo na expressão condicional do ator.

sealed class BankMsg
data class Deposit(val amount: Double) : BankMsg()
data class Withdraw(val amount: Double, val result: CompletableDeferred<Boolean>) : BankMsg()
data class Balance(val result: CompletableDeferred<Double>) : BankMsg()
// Actor holds balance privately — outside code sends messages only

Máquina de estados como ator

Os atores são máquinas de estados naturais: as transições de estado internas acontecem atomicamente em resposta às mensagens.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
enum class TrafficState { RED, GREEN, YELLOW }
fun CoroutineScope.trafficLight() = actor<Unit> {
    var state = TrafficState.RED
    for (msg in channel) {
        state = when (state) {
            TrafficState.RED    -> TrafficState.GREEN
            TrafficState.GREEN  -> TrafficState.YELLOW
            TrafficState.YELLOW -> TrafficState.RED
        }
        println("State: $state")
    }
}
fun main() = runBlocking {
    val light = trafficLight()
    repeat(6) { light.send(Unit) }
    light.close()
}

Construtor de actor()

O construtor de corrotinas actor { } cria um ator com uma caixa de entrada de canal. O ator é uma corrotina que processa mensagens de channel.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.logActor() = actor<String>(capacity = Channel.BUFFERED) {
    val log = mutableListOf<String>()
    for (msg in channel) {
        log.add(msg)
        println("[LOG] $msg")
    }
    println("Log entries: ${log.size}")
}
fun main() = runBlocking {
    val logger = logActor()
    repeat(5) { logger.send("Event $it") }
    logger.close()
    // actor finishes after close
}

Interrompendo um ator

Feche o canal de envio do ator com close(). O laço for no ator termina, permitindo a limpeza antes que a corrotina seja concluída.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val actor = actor<String> {
        for (msg in channel) println("Got: $msg")
        println("Actor done")
    }
    actor.send("hello")
    actor.send("world")
    actor.close()
    // Wait for actor to finish
    delay(50)
}

Atores com contrapressão

Defina a capacidade do canal do ator para aplicar contrapressão — os remetentes ficam suspensos quando a caixa de entrada está cheia.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.slowProcessor() = actor<Int>(capacity = 2) {
    for (item in channel) {
        delay(100) // slow processing
        println("Processed: $item")
    }
}
fun main() = runBlocking {
    val proc = slowProcessor()
    repeat(5) { proc.send(it) } // sender suspends when capacity full
    proc.close()
}

Desempenho: ator versus mutex

Os atores serializam o acesso sem contenção de bloqueios e são adequados para estados complexos com vários tipos de mensagem. O mutex é mais simples para um único contador compartilhado, mas é menos composável.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
// For a simple counter: Mutex is fine
val mutex = Mutex()
var simpleCounter = 0
// For complex state + multiple operations: Actor is cleaner
// Actor: messages describe intent; state changes are encapsulated
fun main() = runBlocking { println("Choose based on state complexity") }

CompletableDeferred para solicitação-resposta

Para padrões de solicitação-resposta dentro de um ator, inclua um CompletableDeferred na mensagem. O ator o conclui; o remetente aguarda o resultado.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
data class Query(val key: String, val reply: CompletableDeferred<String?>)
fun CoroutineScope.cacheActor() = actor<Any> {
    val cache = mutableMapOf<String, String>()
    for (msg in channel) when (msg) {
        is Pair<*, *> -> cache[msg.first as String] = msg.second as String
        is Query -> msg.reply.complete(cache[msg.key])
    }
}

Alternativa moderna: StateFlow + coroutineScope

O construtor actor é experimental e pode ser descontinuado. A alternativa moderna é uma classe ViewModel ou de serviço com um MutableStateFlow atualizado a partir de uma única corrotina.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class CounterService(scope: CoroutineScope) {
    private val _count = MutableStateFlow(0)
    val count = _count.asStateFlow()
    private val events = kotlinx.coroutines.channels.Channel<Unit>()
    init {
        scope.launch {
            for (e in events) _count.value++
        }
    }
    fun increment() { events.trySend(Unit) }
}

Verificação rápida

Como os atores garantem o acesso seguro ao estado concorrente?

Recapitulação

Os atores encapsulam o estado mutável em uma única corrotina e expõem operações como mensagens tipadas de canal. Eles serializam o acesso naturalmente, oferecem suporte a máquinas de estados e eliminam a contenção de bloqueios — ao custo da indireção da passagem de mensagens.

Grátis para começar

Aprenda Kotlin com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
51
Aulas
203

Perguntas Frequentes

A aula “Atores e gerenciamento estruturado de estado” é grátis?

Sim — o texto completo de “Atores e gerenciamento estruturado de estado” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.

O que vou aprender em “Atores e gerenciamento estruturado de estado”?

Use padrões no estilo de atores para serializar o acesso ao estado em código concorrente. Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Kotlin Academy?

Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Atores e gerenciamento estruturado de estado”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Kotlin Academy?

Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Noções básicas de Channel: send, receive e close
  2. Tipos de Channel: rendezvous, com buffer, conflated e ilimitado
  3. Mutex e Semaphore para estado compartilhado
  4. Atores e gerenciamento estruturado de estado
← Voltar para Kotlin Academy