برنامه نویسی

روش های موثر برای استفاده از قفل در کاتلین

Summarize this content to 400 words in Persian Lang
در Kotlin، قفل ها نقش مهمی در تضمین ایمنی نخ ایفا می کنند، زمانی که چندین رشته به منابع مشترک دسترسی دارند. در اینجا روش های اصطلاحی رایج برای استفاده از قفل در Kotlin آمده است:

1. استفاده از ReentrantLock با lock() و unlock()

صریح ترین راه برای استفاده از قفل در کاتلین تماس گرفتن است lock() و unlock() به صورت دستی این کنترل دقیقی را بر روی زمانی که قفل به دست می آید و آزاد می شود، فراهم می کند.

مثال:

import java.util.concurrent.locks.ReentrantLock

class SafeCounter {
private val lock = ReentrantLock()
private var count = 0

fun increment() {
lock.lock() // Explicitly acquire the lock
try {
count++
println(“Incremented to: $count”)
} finally {
lock.unlock() // Ensure the lock is released even if an exception occurs
}
}

fun getCount(): Int {
lock.lock()
return try {
count
} finally {
lock.unlock()
}
}
}

fun main() {
val counter = SafeCounter()
val threads = List(10) {
Thread { counter.increment() }
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(“Final count: ${counter.getCount()}”)
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2. استفاده از withLock تابع پسوند

را withLock تابع افزونه استفاده از قفل را در Kotlin با مدیریت آن ساده می کند lock() و unlock() به طور خودکار تماس می گیرد.

مثال:

import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock

class SafeList {
private val lock = ReentrantLock()
private val list = mutableListOf<String>()

fun add(item: String) {
lock.withLock {
list.add(item)
}
}

fun getList(): List<String> {
lock.withLock {
return list.toList() // Return a copy for safety
}
}
}

fun main() {
val safeList = SafeList()
val threads = List(5) { index ->
Thread {
safeList.add(“Item-$index”)
}
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(“Final list: ${safeList.getList()}”)
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

3. استفاده از synchronized

را synchronized کلمه کلیدی جایگزین ساده تری برای همگام سازی اولیه با قفل کردن روی یک شی مانیتور خاص ارائه می دهد.

مثال:

class SafeCounter {
private var count = 0

fun increment() {
synchronized(this) { // Synchronize on the instance itself
count++
println(“Incremented to: $count”)
}
}

fun getCount(): Int {
synchronized(this) {
return count
}
}
}

fun main() {
val counter = SafeCounter()
val threads = List(10) {
Thread { counter.increment() }
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(“Final count: ${counter.getCount()}”)
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

4. استفاده از ReadWriteLock

برای سناریوهایی با خواندن مکرر و نوشتن نادر، ReadWriteLock قفل های جداگانه ای برای خواندن و نوشتن فراهم می کند که به چندین رشته اجازه می دهد همزمان بخوانند.

مثال:

import java.util.concurrent.locks.ReentrantReadWriteLock

class SafeMap {
private val lock = ReentrantReadWriteLock()
private val map = mutableMapOf<String, String>()

fun put(key: String, value: String) {
lock.writeLock().lock()
try {
map[key] = value
} finally {
lock.writeLock().unlock()
}
}

fun get(key: String): String? {
lock.readLock().lock()
return try {
map[key] } finally {
lock.readLock().unlock()
}
}
}

fun main() {
val safeMap = SafeMap()
val threads = List(5) { index ->
Thread { safeMap.put(“Key-$index”, “Value-$index”) }
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(“Final map: $safeMap”)
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

5. استفاده از Coroutines و Mutex

برای همزمانی مبتنی بر کوروتین، کاتلین این را ارائه می دهد Mutex کلاس از kotlinx.coroutines.sync. این یک قفل معمولی است که از مسدود کردن نخ ها جلوگیری می کند.

مثال:

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

class SafeCounter {
private val mutex = Mutex()
private var count = 0

suspend fun increment() {
mutex.withLock {
count++
println(“Incremented to: $count”)
}
}

fun getCount(): Int = count
}

fun main() = runBlocking {
val counter = SafeCounter()
val jobs = List(10) {
launch {
counter.increment()
}
}
jobs.forEach { it.join() }
println(“Final count: ${counter.getCount()}”)
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

6. استفاده از متغیرهای اتمی

برای سناریوهای ساده، متغیرهای اتمی مانند AtomicInteger و AtomicLong جایگزینی بدون قفل برای شمارنده ها و آکومولاتورهای ایمن با رزوه ارائه کنید.

مثال:

import java.util.concurrent.atomic.AtomicInteger

class SafeCounter {
private val count = AtomicInteger(0)

fun increment() {
println(“Incremented to: ${count.incrementAndGet()}”)
}

fun getCount(): Int = count.get()
}

fun main() {
val counter = SafeCounter()
val threads = List(10) {
Thread { counter.increment() }
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(“Final count: ${counter.getCount()}”)
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چه زمانی از هر کدام استفاده کنیم؟

ReentrantLock + lock/unlock: برای کنترل سطح پایین استفاده کنید، به خصوص زمانی که به ویژگی های پیشرفته مانند قفل های قطع شونده نیاز است.

withLock: رویکرد اصطلاحی کاتلین برای بیشتر موارد استفاده.

synchronized: ساده و سرراست برای همگام سازی اولیه.

ReadWriteLock: ایده آل برای خواندن مکرر و نوشتن نادر.

Mutex: بهترین برای همزمانی مبتنی بر کوروتین.

متغیرهای اتمی: سبک و بدون قفل، مناسب برای شمارنده و آکومولاتور.

هر رویکرد نیازهای خاصی را بر اساس پیچیدگی، عملکرد، و اینکه آیا شما با رشته‌ها یا کوروتین‌ها کار می‌کنید، برآورده می‌کند. درک این گزینه ها تضمین می کند که می توانید برنامه های همزمان ایمن و کارآمد Kotlin را بنویسید.

در Kotlin، قفل ها نقش مهمی در تضمین ایمنی نخ ایفا می کنند، زمانی که چندین رشته به منابع مشترک دسترسی دارند. در اینجا روش های اصطلاحی رایج برای استفاده از قفل در Kotlin آمده است:


1. استفاده از ReentrantLock با lock() و unlock()

صریح ترین راه برای استفاده از قفل در کاتلین تماس گرفتن است lock() و unlock() به صورت دستی این کنترل دقیقی را بر روی زمانی که قفل به دست می آید و آزاد می شود، فراهم می کند.

مثال:

import java.util.concurrent.locks.ReentrantLock

class SafeCounter {
    private val lock = ReentrantLock()
    private var count = 0

    fun increment() {
        lock.lock() // Explicitly acquire the lock
        try {
            count++
            println("Incremented to: $count")
        } finally {
            lock.unlock() // Ensure the lock is released even if an exception occurs
        }
    }

    fun getCount(): Int {
        lock.lock()
        return try {
            count
        } finally {
            lock.unlock()
        }
    }
}

fun main() {
    val counter = SafeCounter()
    val threads = List(10) {
        Thread { counter.increment() }
    }
    threads.forEach { it.start() }
    threads.forEach { it.join() }
    println("Final count: ${counter.getCount()}")
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


2. استفاده از withLock تابع پسوند

را withLock تابع افزونه استفاده از قفل را در Kotlin با مدیریت آن ساده می کند lock() و unlock() به طور خودکار تماس می گیرد.

مثال:

import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock

class SafeList {
    private val lock = ReentrantLock()
    private val list = mutableListOf<String>()

    fun add(item: String) {
        lock.withLock {
            list.add(item)
        }
    }

    fun getList(): List<String> {
        lock.withLock {
            return list.toList() // Return a copy for safety
        }
    }
}

fun main() {
    val safeList = SafeList()
    val threads = List(5) { index ->
        Thread {
            safeList.add("Item-$index")
        }
    }
    threads.forEach { it.start() }
    threads.forEach { it.join() }
    println("Final list: ${safeList.getList()}")
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


3. استفاده از synchronized

را synchronized کلمه کلیدی جایگزین ساده تری برای همگام سازی اولیه با قفل کردن روی یک شی مانیتور خاص ارائه می دهد.

مثال:

class SafeCounter {
    private var count = 0

    fun increment() {
        synchronized(this) { // Synchronize on the instance itself
            count++
            println("Incremented to: $count")
        }
    }

    fun getCount(): Int {
        synchronized(this) {
            return count
        }
    }
}

fun main() {
    val counter = SafeCounter()
    val threads = List(10) {
        Thread { counter.increment() }
    }
    threads.forEach { it.start() }
    threads.forEach { it.join() }
    println("Final count: ${counter.getCount()}")
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


4. استفاده از ReadWriteLock

برای سناریوهایی با خواندن مکرر و نوشتن نادر، ReadWriteLock قفل های جداگانه ای برای خواندن و نوشتن فراهم می کند که به چندین رشته اجازه می دهد همزمان بخوانند.

مثال:

import java.util.concurrent.locks.ReentrantReadWriteLock

class SafeMap {
    private val lock = ReentrantReadWriteLock()
    private val map = mutableMapOf<String, String>()

    fun put(key: String, value: String) {
        lock.writeLock().lock()
        try {
            map[key] = value
        } finally {
            lock.writeLock().unlock()
        }
    }

    fun get(key: String): String? {
        lock.readLock().lock()
        return try {
            map[key]
        } finally {
            lock.readLock().unlock()
        }
    }
}

fun main() {
    val safeMap = SafeMap()
    val threads = List(5) { index ->
        Thread { safeMap.put("Key-$index", "Value-$index") }
    }
    threads.forEach { it.start() }
    threads.forEach { it.join() }
    println("Final map: $safeMap")
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


5. استفاده از Coroutines و Mutex

برای همزمانی مبتنی بر کوروتین، کاتلین این را ارائه می دهد Mutex کلاس از kotlinx.coroutines.sync. این یک قفل معمولی است که از مسدود کردن نخ ها جلوگیری می کند.

مثال:

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

class SafeCounter {
    private val mutex = Mutex()
    private var count = 0

    suspend fun increment() {
        mutex.withLock {
            count++
            println("Incremented to: $count")
        }
    }

    fun getCount(): Int = count
}

fun main() = runBlocking {
    val counter = SafeCounter()
    val jobs = List(10) {
        launch {
            counter.increment()
        }
    }
    jobs.forEach { it.join() }
    println("Final count: ${counter.getCount()}")
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


6. استفاده از متغیرهای اتمی

برای سناریوهای ساده، متغیرهای اتمی مانند AtomicInteger و AtomicLong جایگزینی بدون قفل برای شمارنده ها و آکومولاتورهای ایمن با رزوه ارائه کنید.

مثال:

import java.util.concurrent.atomic.AtomicInteger

class SafeCounter {
    private val count = AtomicInteger(0)

    fun increment() {
        println("Incremented to: ${count.incrementAndGet()}")
    }

    fun getCount(): Int = count.get()
}

fun main() {
    val counter = SafeCounter()
    val threads = List(10) {
        Thread { counter.increment() }
    }
    threads.forEach { it.start() }
    threads.forEach { it.join() }
    println("Final count: ${counter.getCount()}")
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


چه زمانی از هر کدام استفاده کنیم؟

  • ReentrantLock + lock/unlock: برای کنترل سطح پایین استفاده کنید، به خصوص زمانی که به ویژگی های پیشرفته مانند قفل های قطع شونده نیاز است.
  • withLock: رویکرد اصطلاحی کاتلین برای بیشتر موارد استفاده.
  • synchronized: ساده و سرراست برای همگام سازی اولیه.
  • ReadWriteLock: ایده آل برای خواندن مکرر و نوشتن نادر.
  • Mutex: بهترین برای همزمانی مبتنی بر کوروتین.
  • متغیرهای اتمی: سبک و بدون قفل، مناسب برای شمارنده و آکومولاتور.

هر رویکرد نیازهای خاصی را بر اساس پیچیدگی، عملکرد، و اینکه آیا شما با رشته‌ها یا کوروتین‌ها کار می‌کنید، برآورده می‌کند. درک این گزینه ها تضمین می کند که می توانید برنامه های همزمان ایمن و کارآمد Kotlin را بنویسید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا