Mutex e Semaphore para estado compartilhado
Proteja o estado mutável compartilhado usando Mutex e limite a concorrência com Semaphore.
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.
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
- Noções básicas de Channel: send, receive e close
- Tipos de Channel: rendezvous, com buffer, conflated e ilimitado
- Mutex e Semaphore para estado compartilhado
- Atores e gerenciamento estruturado de estado