Sobes.tech
Middle+

Korutinlerle çalışırken senkronizasyon blokları ve benzer yapıları kullanmak neden önerilmez?

sobes.tech yapay zeka

AI'dan gelen yanıt

Korutinalar ile çalışırken synchronized veya standart kütüphaneden lock gibi engelleyici yapılar kullanmak, kaynakların verimsiz kullanılmasına yol açar ve sorunlara neden olabilir.

Ana nedenler:

  • İş parçacığı engellemesi: Senkronizasyon blokları, sadece korutinleri değil, aynı zamanda iş parçacığını durdurur. Eğer senkronize edilmiş bir blok içinde Suspending fonksiyonu çalıştırılırsa, iş parçacığı, Suspending fonksiyonu tamamlanıp kilit serbest bırakılana kadar engellenir. Bu, aynı iş parçacığını kullanan diğer korutinlerin açlık yaşamasına neden olabilir.
  • Suspending fonksiyonlarla uyumsuzluk: Korutinlerin çalışma mekanizması (bağlam değişimi, devamlar) iş parçacığı seviyesindeki kilitleri dikkate almaz. Bir Suspending fonksiyonun senkronize blok içinde çalıştırılması, korutinlerin bloklamayan doğasını bozar.
  • Yapılandırılmış eşzamanlılık ilkelerinin ihlali: Korutinler, kendi iptal işaretleri ve hiyerarşisine sahiptir. İş parçacığı seviyesindeki kilitler bu sistemi görmezden gelir, iptal işlemlerinin doğru yönetimini ve yaşam döngüsü kontrolünü zorlaştırır.
  • Deadlock riski: İş parçacığı kilitleri ve korutin eşzamanlılık mekanizmalarının kombinasyonu, karmaşık deadlock'ların oluşma olasılığını artırır ve bunların hata ayıklamasını zorlaştırır.

İş parçacığı seviyesindeki kilitler yerine, kotlinx.coroutines kütüphanesinden özel eşzamanlılık primitive'leri kullanmak gerekir:

  • Mutex: Karşılıklı dışlama sağlar. Bir mutex'i almak isteyen korutin, mutex kullanılıyorsa askıya alınır (iş parçacığını engellemeden) ve mutex serbest bırakılana kadar bekler.
  • Semaphore: Aynı anda kaynak erişimi sınırlar.
  • Channel: Korutinler arasında veri alışverişi için kullanılır.
  • Atomic variables: Basit atomik işlemler için.

Mutex kullanım örneği:

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

val mutex = Mutex()
var counter = 0

suspend fun incrementCounter() {
    mutex.withLock {
        // Kritik bölüm
        counter++
    }
}

fun main() = runBlocking {
    // Eşzamanlı erişim için çok sayıda korutin oluşturuyoruz
    repeat(1000) {
        launch {
            incrementCounter()
        }
    }
    delay(1000) // Korutinlerin çalışması için zaman tanıyoruz
    println("Counter: $counter") // 1000 bekleniyor
}

mutex.withLock bir suspending fonksiyondur. Eğer mutex meşgulse, withLock'u çağıran korutin askıya alınır ve diğer görevlere thread serbest bırakılır. Mutex kullanılabilir hale geldiğinde, korutin devam eder. Bu, synchronized'tan farklı olarak thread'i engellemez.