Middle+
Miért nem ajánlott szinkronizációs blokkokat és hasonló szerkezeteket használni korutinokkal való munka során?
sobes.tech MI
Válasz az MI-től
A blokkoló szerkezetek, például a synchronized vagy a lock a standard könyvtárból, a korutinokkal való munka során az erőforrások nem hatékony kihasználásához vezethetnek, és problémákat okozhatnak.
Fő okok:
- Szál blokkolása: A szinkronizációs blokkok megállítják a szál végrehajtását, nem csak a korutinokat. Ha egy Suspending függvény egy szinkronizált blokkban fut, akkor a szál blokkolva marad, amíg a Suspending függvény be nem fejeződik, és a zárolás fel nem oldódik. Ez más korutinoknak is lehetőséget ad arra, hogy ugyanazt a szálat használják, ami éhezést okozhat.
- Kompatibilitás a Suspending függvényekkel: A korutinok működési mechanizmusa (környezetváltás, folytatások) nem veszi figyelembe a szál szintű zárolásokat. Egy Suspending függvény futtatása szinkronizált blokkban megsérti a korutinok nem blokkoló természetét.
- A strukturált konkurencia elveinek megsértése: A korutinok saját leállítási és hierarchikus rendszerrel rendelkeznek. A szál szintű zárolások figyelmen kívül hagyják ezt a rendszert, megnehezítve a helyes leállításkezelést és az életciklus irányítását.
- Deadlock kockázat: A szálak zárolásainak és a korutinok mechanizmusainak kombinációja növeli a komplex deadlockok kialakulásának valószínűségét, amelyek nehezen hibakereshetők.
A szál szintű zárolások helyett a kotlinx.coroutines könyvtárból származó speciális konkurencia primitíveket kell használni:
Mutex: Biztosítja a kölcsönös kizárást. Az a korutin, amely megpróbál egy foglalt mutexet megszerezni, szünetel (szál blokkolása nélkül) addig, amíg a mutex fel nem szabadul.Semaphore: Korlátozza a párhuzamosan hozzáférő korutinok számát.Channel: Adatok cseréjére használják a korutinok között.Atomiás változók: Egyszerű atomikus műveletekhez.
A Mutex használatának példája:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.*
val mutex = Mutex()
var counter = 0
suspend fun incrementCounter() {
mutex.withLock {
// Kritikus szakasz
counter++
}
}
fun main() = runBlocking {
// Több korutin létrehozása párhuzamos hozzáféréshez
repeat(1000) {
launch {
incrementCounter()
}
}
delay(1000) // Időt adunk a korutinoknak a futtatáshoz
println("Counter: $counter") // Várható érték 1000
}
A mutex.withLock egy suspending-függvény. Ha a mutex foglalt, a withLock-ot hívó korutin szünetel, és felszabadítja a szálat más feladatok számára. Amikor a mutex elérhetővé válik, a korutin folytatódik. Ez nem blokkolja a szálat, ellentétben a synchronized-del.