Mutex och Semaphore för delat tillstånd
Skydda delat föränderligt tillstånd med Mutex och begränsa samtidighet med Semaphore.
Mutex och Semaphore för delat tillstånd är en gratis lektion i Kotlin Academy på CoddyKit. Detta är lektion 3 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Kotlin Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Kotlin Academy innehåller totalt 4 lektioner.
Problemet med delat tillstånd
Koroutiner på flera trådar kan förstöra delat, muterbart tillstånd. Utan synkronisering ger samtidiga inkrementeringar felaktiga resultat.
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
}Grunderna i Mutex
Mutex är ett lås för ömsesidig uteslutning mellan koroutiner. Det suspenderar (blockerar inte) anroparen tills låset är tillgängligt.
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
}Tillägget withLock
mutex.withLock { ... } hämtar låset, kör blocket och släpper låset — även vid undantag eller avbrytning.
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 manuellt
Ni kan anropa lock() och unlock() direkt för finare kontroll, men föredra withLock för att undvika att glömma låsa upp.
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
}
}Mutex är inte rekursivt
Kotlin:s Mutex är INTE rekursivt. Om ni anropar lock() igen från samma koroutin uppstår ett deadlock. Använd en räknare eller strukturera om koden för att undvika kapslade lås.
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")
}
}Grunderna i Semaphore
En Semaphore(n) låter upp till n koroutiner fortsätta samtidigt. Den fungerar som ett biljettsystem med n platser.
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() }
}Tillägget withPermit
semaphore.withPermit { ... } hämtar ett tillstånd, kör blocket och släpper tillståndet — den koroutinsäkra motsvarigheten till att försöka hämta ett tillstånd från en semafor.
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)
}Begränsa anropstakten med Semaphore
Använd en semafor för att begränsa antalet samtidiga API-anrop — begränsa till N förfrågningar åt gången.
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 jämfört med Semaphore
Mutex: binär semafor (1 tillstånd), för exklusiv åtkomst. Semaphore(n): n tillstånd, för begränsad samtidighet. Använd Mutex för att skydda en resurs och Semaphore för att begränsa parallellism.
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") }Atomär räknare med Mutex
Implementera en trådsäker räknarklass med Mutex för att skydda inkrementeringar och avläsningar.
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()}")
}Alternativ: entrådad dispatcher
I stället för ett mutex kan ni begränsa det muterbara tillståndet till en entrådad dispatcher. Endast en koroutin körs på den dispatchern åt gången, vilket gör åtkomsten säker av sig själv.
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()
}Snabbtest
Vad är den viktigaste skillnaden mellan Mutex och Semaphore?
Sammanfattning
Mutex ger exklusiv åtkomst till delat tillstånd — föredra withLock. Semaphore(n) begränsar samtidigheten till n. Båda suspenderar (blockerar inte) väntande koroutiner. För enkla fall är en entrådad dispatcher ofta renare.
Lär dig Kotlin med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 51
- Lektioner
- 203
Vanliga frågor
Är lektionen ”Mutex och Semaphore för delat tillstånd” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Kotlin Academy, inklusive ”Mutex och Semaphore för delat tillstånd”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Kotlin Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Mutex och Semaphore för delat tillstånd”?
Skydda delat föränderligt tillstånd med Mutex och begränsa samtidighet med Semaphore. Ni övar på Kotlin Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Kotlin Academy?
Du behöver inga förkunskaper. Utbildningen i Kotlin Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Mutex och Semaphore för delat tillstånd”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Kotlin Academy-lektionen?
Ja. Varje Kotlin Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Grunderna i Channel: send, receive och close
- Channel-typer: Rendezvous, Buffered, Conflated, Unlimited
- Mutex och Semaphore för delat tillstånd
- Aktörer och strukturerad tillståndshantering