Sobes.tech
Middle+

Miks ei soovitata kasutada sünkroniseerimisblokke ja sarnaseid konstruktsioone korutinitega töötades?

sobes.tech AI

Vastus AI-lt

Kasutades blokeerivaid konstruktsioone nagu synchronized või lock standardraamatukogust, korutinidega töötamisel viib see ressursside ebatõhusa kasutamiseni ning võib põhjustada probleeme.

Peamised põhjused:

  • Niidi lukustamine: Sünkroniseerimisblokid peatavad niidi täitmise, mitte ainult korutinad. Kui sünkroniseeritud bloki sees käivitatakse Suspending-funktsioon, siis niit lukustatakse kuni Suspending-funktsiooni lõpetamiseni ja lukustus vabastamiseni. See võib viia teiste korutinate "nälga", mis kasutavad sama niiti.
  • Nesobivus Suspending-funktsioonidega: Korutinate töö mehhanism (konteksti vahetamine, jätkamine) ei arvesta niidi taseme lukustusi. Suspending-funktsiooni täitmine sünkroniseeritud bloki sees rikub korutinate mitteblokeeriva olemuse.
  • Struktureeritud konkurentsi põhimõtete rikkumine: Korutinatel on oma märgistussüsteem ja hierarhia. Niidi taseme lukustused ignoreerivad seda süsteemi, muutes keerulisemaks õige tühistamise töötlemise ja elutsükli juhtimise.
  • Düslokide risk: Niidi taseme lukustused ja korutinate konkurentsimehhanismide kombinatsioon suurendab keeruliste düslokkide tekkimise tõenäosust, mis on raskesti diagnoositavad ja parandatavad.

Asendama niidi taseme lukustusi, et sünkroniseerida juurdepääs jagatud ressurssidele korutinates, tuleks kasutada spetsialiseeritud konkurentsi primitiive kotlinx.coroutines raamatukogust:

  • Mutex: Tagab vastastikuse välistamise. Korutina, kes üritab haarata hõivatud mutexi, peatub (ilma niidi blokeerimiseta) kuni mutex vabastatakse.
  • Semaphore: Piirab korutinate arvu, kellel on samaaegselt juurdepääs ressursile.
  • Channel: Kasutatakse andmete vahetamiseks korutinite vahel.
  • Atomic variables: Lihtsate atomaarsete operatsioonide jaoks.

Mutex kasutamise näide:

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

val mutex = Mutex()
var counter = 0

suspend fun incrementCounter() {
    mutex.withLock {
        // Kriitiline sektsioon
        counter++
    }
}

fun main() = runBlocking {
    // Korutinate kogumi loomine konkurentsivõimelise juurdepääsu jaoks
    repeat(1000) {
        launch {
            incrementCounter()
        }
    }
    delay(1000) // Aeg korutinidele täitmiseks
    println("Counter: $counter") // Ootame 1000
}

mutex.withLock on suspending-funktsioon. Kui mutex on hõivatud, peatub korutina, kes seda kutsub, ja vabastab niidi teiste ülesannete jaoks. Kui mutex muutub saadaval olevaks, jätkub korutina. See ei blokeeri niiti, erinevalt synchronized-ist.