Middle+
Ako možno implementovať synchronizáciu v Kotlin pomocou coroutines?
sobes.tech AI
Odpoveď od AI
Synchronizácia v Kotlin korutinách sa dosahuje pomocou špeciálnych primitívov a dátových štruktúr z knižnice kotlinx.coroutines.
Hlavné prístupy:
-
Mutex
- Poskytuje vzájomné vylúčenie na ochranu kritických sekcií kódu.
- Korutina, ktorá sa pokúsi získať Mutex, sa zablokuje, kým nebude uvoľnený.
- Má funkcie
lock()aunlock(), ako aj idiomatickýwithLock.
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.* val mutex = Mutex() var counter = 0 suspend fun increment() { mutex.withLock { counter++ } } suspend fun main() = coroutineScope { repeat(10_000) { launch { increment() } } println(counter) // Očakávame 10000 } -
Semaphore
- Obmedzuje počet korutín, ktoré môžu súčasne získať prístup ku zdroju alebo vykonať určitý blok kódu.
- Riadi skupinu povolení.
- Má funkcie
acquire()arelease(), ako ajwithPermit.
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.* val semaphore = Semaphore(2) // Súčasne môžu pracovať 2 korutiny suspend fun doLimitedWork(id: Int) { semaphore.withPermit { println("Korutina $id získala povolenie. Pracuje...") delay(100) // Imitácia práce println("Korutina $id uvoľnila povolenie.") } } suspend fun main() = coroutineScope { repeat(5) { i -> launch { doLimitedWork(i) } } } -
Atómové operácie (z
kotlinx.coroutines.atomic)- Poskytujú bezpečné operácie nad primitívnymi typmi a referenciami.
- Používajú nízkoúrovňové CPU inštrukcie (CAS - Compare-and-Swap).
- Vhodné pre jednoduché operácie bez explicitných zámkov.
import kotlinx.coroutines.atomic.AtomicInt import kotlinx.coroutines.* val atomicCounter = AtomicInt(0) suspend fun atomicIncrement() { atomicCounter.incrementAndGet() } suspend fun main() = coroutineScope { repeat(10_000) { launch { atomicIncrement() } } println(atomicCounter.value) // Očakávame 10000 } -
Zdieľané dátové štruktúry na dispatcheri s jedným vláknom
- Najjednoduchší prístup. Spustenie korutín na kontexte s jedným vláknom (
Dispatchers.Default.limitedParallelism(1)alebonewSingleThreadContext) garantuje sekvenčné vykonávanie kódu, čím sa vylúčia závody dát. Nie je to explicitný primitív na synchronizáciu, ale zabezpečuje synchronizáciu prostredníctvom serializácie prístupu.
import kotlinx.coroutines.* val mySingleThreadContext = newSingleThreadContext("SingleThread") var sharedData = mutableListOf<Int>() suspend fun addToSharedData(value: Int) { sharedData.add(value) // Bezpečné, pretože sa vykonáva na jednom vlákne } suspend fun main() = withContext(mySingleThreadContext) { repeat(10_000) { launch { addToSharedData(it) } } println(sharedData.size) // Očakávame 10000 } - Najjednoduchší prístup. Spustenie korutín na kontexte s jedným vláknom (
-
Kanály
- Nie sú primitívmi na synchronizáciu v čistej podobe, ale môžu byť použité na bezpečný prenos dát medzi korutinami, čím nepriamo riešia problémy synchronizácie prístupu k prenášaným dátam.
- Poskytujú spôsob prenosu toku dát z jednej korutiny do druhej.
Výber prístupu závisí od scenára použitia. Mutex a Semaphore poskytujú klasické mechanizmy blokovania, atomické operácie sú efektívne pre jednoduché atomické aktualizácie, a dispatcher s jedným vláknom je vhodný, keď má byť prístup k spoločným dátam prísne sekvenčný. Kanály sa používajú na komunikáciu a koordináciu, nie na priame zabezpečenie spoločných zdrojov.