Kotlin Academy · Aula

Mutex e Semaphore para estado compartilhado

Proteja o estado mutável compartilhado usando Mutex e limite a concorrência com Semaphore.

Aula 3 de 413 etapas

Mutex e Semaphore para estado compartilhado é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 3 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 problema do estado compartilhado

Corrotinas em várias threads podem corromper o estado mutável compartilhado. Sem sincronização, incrementos simultâneos produzem resultados incorretos.

import kotlinx.coroutines.*
fun main() = runBlocking {
    var counter = 0
    val jobs = List(1000) {
        launch(Dispatchers.Default) { counter++ } // race condition!
    }
    jobs.forEach { it.join() }
    println("Expected 1000, got: $counter") // likely wrong
}

Noções básicas de mutex

Mutex é um bloqueio de exclusão mútua para corrotinas. Ele suspende (não bloqueia) o chamador até que o bloqueio esteja disponível.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    var counter = 0
    val jobs = List(1000) {
        launch(Dispatchers.Default) {
            mutex.withLock { counter++ }  // safe
        }
    }
    jobs.forEach { it.join() }
    println("Counter: $counter") // 1000
}

Extensão withLock

mutex.withLock { ... } adquire o bloqueio, executa o bloco e o libera — mesmo em caso de exceção ou cancelamento.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    var list = mutableListOf<Int>()
    List(10) {
        launch {
            mutex.withLock {
                list.add(it)
            }
        }
    }.forEach { it.join() }
    println(list.sorted())
}

lock / unlock manualmente

Você pode chamar lock() e unlock() diretamente para ter um controle mais preciso, mas prefira withLock para evitar esquecer-se de liberar o bloqueio.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    mutex.lock()
    try {
        println("Critical section")
    } finally {
        mutex.unlock()  // must always release
    }
}

O mutex não é reentrante

O Mutex do Kotlin não é reentrante. Chamar lock() novamente da mesma corrotina causará um deadlock. Use um contador ou refatore o código para evitar bloqueios aninhados.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val mutex = Mutex()
    // This deadlocks:
    // mutex.withLock { mutex.withLock { println("never") } }
    mutex.withLock {
        println("Acquired once — safe")
    }
}

Noções básicas de semáforo

Um Semaphore(n) permite que até n corrotinas prossigam simultaneamente. É como um sistema de bilhetes com n vagas.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val semaphore = Semaphore(3) // max 3 concurrent
    List(10) { i ->
        launch {
            semaphore.withPermit {
                println("Concurrent task $i"); delay(100)
            }
        }
    }.forEach { it.join() }
}

Extensão withPermit

semaphore.withPermit { ... } adquire uma permissão, executa o bloco e a libera — o equivalente seguro para corrotinas à tentativa de aquisição de um semáforo.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
fun main() = runBlocking {
    val sem = Semaphore(2)
    val results = mutableListOf<String>()
    List(5) { i ->
        launch {
            sem.withPermit {
                delay(50)
                synchronized(results) { results.add("task-$i") }
            }
        }
    }.forEach { it.join() }
    println(results)
}

Limitação de taxa com semáforo

Use um semáforo para limitar a taxa de chamadas simultâneas à interface de programação de aplicações — limite a N solicitações por vez.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
val apiSemaphore = Semaphore(5) // max 5 concurrent requests
suspend fun callApi(id: Int): String {
    return apiSemaphore.withPermit {
        delay(100) // simulate network
        "Response-$id"
    }
}
fun main() = runBlocking {
    val results = (1..20).map { async { callApi(it) } }.awaitAll()
    println("Got ${results.size} responses")
}

Mutex versus semáforo

Mutex: semáforo binário (1 permissão), para acesso exclusivo. Semaphore(n): n permissões, para simultaneidade limitada. Use Mutex para proteger um recurso e Semaphore para limitar o paralelismo.

import kotlinx.coroutines.sync.*
// Mutex = Semaphore(1) for exclusive access
// Semaphore(n) = n-way concurrency limit
val exclusive = Mutex()          // one at a time
val limited   = Semaphore(3)     // three at a time
fun main() { println("Mutex for exclusion; Semaphore for rate limiting") }

Contador atômico com mutex

Implemente uma classe de contador segura para execução concorrente usando Mutex para proteger incrementos e leituras.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
class AtomicCounter {
    private val mutex = Mutex()
    private var count = 0
    suspend fun increment() = mutex.withLock { count++ }
    suspend fun get() = mutex.withLock { count }
}
fun main() = runBlocking {
    val counter = AtomicCounter()
    List(100) { launch { counter.increment() } }.forEach { it.join() }
    println("Count: ${counter.get()}")
}

Alternativa: despachador de thread única

Em vez de usar um mutex, confine o estado mutável a um despachador de thread única. Apenas uma corrotina é executada nesse despachador por vez, tornando o acesso inerentemente seguro.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val singleThread = newSingleThreadContext("CounterThread")
    var counter = 0
    List(1000) {
        launch(singleThread) { counter++ }
    }.forEach { it.join() }
    println("Counter: $counter") // 1000, no mutex needed
    singleThread.close()
}

Verificação rápida

Qual é a principal diferença entre Mutex e Semaphore?

Recapitulação

mutex fornece acesso exclusivo ao estado compartilhado — prefira withLock. semáforo(n) limita a simultaneidade a n. Ambos suspendem (não bloqueiam) as corrotinas em espera. Em casos simples, um despachador de thread única costuma ser mais claro.

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 “Mutex e Semaphore para estado compartilhado” é grátis?

Sim — o texto completo de “Mutex e Semaphore para estado compartilhado” é 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 “Mutex e Semaphore para estado compartilhado”?

Proteja o estado mutável compartilhado usando Mutex e limite a concorrência com Semaphore. 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 3 de 4.

Quanto tempo leva a aula “Mutex e Semaphore para estado compartilhado”?

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