Sobes.tech
Middle+

Zašto se ne preporučuje korišćenje blokova sinhronizacije i sličnih konstrukcija prilikom rada sa korutinama?

sobes.tech АИ

Одговор од АИ

Korišćenje blokirajućih konstrukcija kao što su synchronized ili lock iz standardne biblioteke pri radu sa korutinama dovodi do neefikasnog korišćenja resursa i može izazvati probleme.

Glavni razlozi:

  • Zaključavanje niti: Sinhronizacijski blokovi zaustavljaju izvršavanje nit, a ne samo korutina. Ako se unutar sinhronizovanog bloka izvršava Suspending-funkcija, nit će biti blokirana dok Suspending-funkcija ne završi i zaključavanje ne bude oslobođeno. To može dovesti do "gladovanja" drugih korutina koje koriste istu nit.
  • Nespojivost sa Suspending-funkcijama: Mehanizam rada sa korutinama (prebacivanje konteksta, nastavci) ne uzima u obzir zaključavanja na nivou niti. Izvršavanje Suspending-funkcije unutar sinhronizovanog bloka narušava bezblokirajuću prirodu korutina.
  • Prekršaj principa strukturirane konkurencije: Korutine imaju svoj sistem oznaka za otkazivanje i hijerarhiju. Zaključavanja na nivou niti ignorišu taj sistem, otežavajući pravilnu obradu otkazivanja i upravljanje životnim ciklusom.
  • Rizik od deadlock-ova: Kombinacija zaključavanja niti i mehanizama konkurentnosti korutina povećava verovatnoću nastanka složenih deadlock-ova, koji su teško otklonjivi.

Umesto zaključavanja na nivou niti za sinhronizaciju pristupa deljenim resursima u korutinama, treba koristiti specijalizovane primitivne mehanizme konkurentnosti iz biblioteke kotlinx.coroutines:

  • Mutex: Osigurava međusobno isključivanje. Korutina koja pokuša da zauzme već zauzet mutex, zaustaviće se (bez blokiranja niti) dok mutex ne bude oslobođen.
  • Semaphore: Ograničava broj korutina koje istovremeno imaju pristup resursu.
  • Channel: Koristi se za razmenu podataka između korutina.
  • Atomic variables: Za jednostavne atomarne operacije.

Primer korišćenja Mutex:

import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.*

val mutex = Mutex()
var counter = 0

suspend fun incrementCounter() {
    mutex.withLock {
        // Kritična sekcija
        counter++
    }
}

fun main() = runBlocking {
    // Kreiramo skup korutina za konkurentan pristup
    repeat(1000) {
        launch {
            incrementCounter()
        }
    }
    delay(1000) // Dajemo vremena korutinama da se izvrše
    println("Counter: $counter") // Očekujemo 1000
}

mutex.withLock je suspending-funkcija. Ako je mutex zauzet, korutina koja je pozvala withLock će se zaustaviti i osloboditi nit za druge zadatke. Kada mutex postane dostupan, korutina će se nastaviti. Ovo ne blokira nit, za razliku od synchronized.