Middle+
Kotlin'de koroutinler kullanarak senkronizasyon nasıl gerçekleştirilebilir?
sobes.tech yapay zeka
AI'dan gelen yanıt
Kotlin coroutinelerinde senkronizasyon, kotlinx.coroutines kütüphanesinden özel primitive ve veri yapıları kullanılarak sağlanır.
Ana yaklaşımlar:
-
Mutex
- Kritik kod bölümlerini korumak için karşılıklı dışlama sağlar.
- Mutex'i almak isteyen coroutine, serbest bırakılana kadar bloklanır.
lock()veunlock()fonksiyonlarına ek olarak, daha idiomatik olanwithLockfonksiyonuna sahiptir.
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) // Beklenen 10000 } -
Semaphore
- Aynı anda erişebilecek coroutine sayısını veya belirli bir kod bloğunu çalıştırabilecek coroutine sayısını sınırlar.
- İzin havuzunu yönetir.
acquire()verelease()fonksiyonlarına ek olarakwithPermitsağlar.
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.* val semaphore = Semaphore(2) // Aynı anda 2 coroutine çalışabilir suspend fun doLimitedWork(id: Int) { semaphore.withPermit { println("Coroutine $id izin aldı. Çalışıyor...") delay(100) // Çalışmayı taklit et println("Coroutine $id izin verdi.") } } suspend fun main() = coroutineScope { repeat(5) { i -> launch { doLimitedWork(i) } } } -
Atomik işlemler (
kotlinx.coroutines.atomic'den)- Primitif tipler ve referanslar üzerinde thread-safe işlemler sağlar.
- Düşük seviyeli CPU talimatlarını (CAS - Compare-and-Swap) kullanır.
- Açık kilitler olmadan basit işlemler için uygundur.
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) // Beklenen 10000 } -
Tek iş parçacıklı dağıtıcı üzerinde paylaşılan veri yapıları
- En basit yaklaşım. Kodun sıralı yürütülmesini garanti eden tek iş parçacıklı bağlamda (
Dispatchers.Default.limitedParallelism(1)veyanewSingleThreadContext) çalıştırmak, yarış koşullarını önler. Açık bir senkronizasyon primitive değildir, ancak erişimi seri hale getirerek senkronizasyon sağlar.
import kotlinx.coroutines.* val mySingleThreadContext = newSingleThreadContext("SingleThread") var sharedData = mutableListOf<Int>() suspend fun addToSharedData(value: Int) { sharedData.add(value) // Güvenli, çünkü tek bir iş parçacığında çalışıyor } suspend fun main() = withContext(mySingleThreadContext) { repeat(10_000) { launch { addToSharedData(it) } } println(sharedData.size) // Beklenen 10000 } - En basit yaklaşım. Kodun sıralı yürütülmesini garanti eden tek iş parçacıklı bağlamda (
-
Kanallar
- Kendisi doğrudan senkronizasyon primitive değildir, ancak koroutinler arasında güvenli veri iletimi için kullanılabilir, bu da iletilen verilere erişimdeki senkronizasyon sorunlarını dolaylı olarak çözer.
- Bir koroutinden diğerine veri akışını iletmek için bir yol sağlar.
Kullanım senaryosuna bağlı olarak yaklaşım seçilir. Mutex ve Semaphore klasik kilitleme mekanizmaları sağlar, Atomik işlemler basit atomik güncellemeler için etkilidir, ve tek iş parçacıklı dağıtıcı, paylaşılan verilere erişimin kesinlikle sıralı olması gerektiğinde kullanışlıdır. Kanallar ise iletişim ve koordinasyon için kullanılır, doğrudan paylaşılan kaynakların korunması için değil.