本文首發於公眾號“AntDream”,歡迎微信搜索“AntDream”或掃描文章底部二維碼關注,和我一起每天進步一點點
Kotlin 語言提供了多種機制來處理併發和同步,其中包括高層次和低層次的工具。對於常規的併發任務,可以利用 Kotlin 協程提供的結構化併發方式。而對於需要更低層次的鎖定機制,可以使用 Mutex 來實現對共享資源的線程安全訪問。
Kotlin 協程與併發(Coroutines and Concurrency)
協程是一種輕量級的線程,可以通過 kotlinx.coroutines 庫來實現。協程為結構化併發提供了強大的支持,使得編寫異步、併發代碼變得更加簡單和直觀。
協程基礎
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
在這個例子中,runBlocking 函數用於啓動一個新的協程並阻塞當前線程,而 launch 函數則用於啓動一個新的協程,並在1秒後輸出 "World!"。
併發與同步
當多個協程需要訪問共享資源時,需要一些同步機制來防止數據競爭。一個常用的方法是使用 Kotlin 庫提供的 Mutex。
Mutex
Mutex(互斥鎖)是一種用於保證互斥訪問共享資源的同步機制。Mutex 確保在同一時刻只有一個協程能夠訪問被保護的代碼塊或資源,從而避免競爭條件。
使用 Mutex
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
val mutex = Mutex()
var counter = 0
fun main() = runBlocking {
val jobs = List(100) {
launch {
repeat(1000) {
// 在這裏使用 mutex 來保護對 counter 的訪問
mutex.withLock {
counter++
}
}
}
}
jobs.forEach { it.join() }
println("Counter = $counter")
}
在這個例子中,我們創建了100個協程,每個協程重複1000次對共享變量 counter 的訪問。使用 mutex.withLock 保證了每次只有一個協程能訪問 counter,從而避免併發問題。
withLock() 是一種便捷方法,用於在鎖內執行給定的代碼塊。它會自動處理獲取和釋放鎖,確保即使在代碼塊中發生異常,也會正確釋放鎖。
Mutex 的其他方法
lock:掛起直到互斥鎖被鎖定。
lock() 方法用於嘗試獲取鎖。如果鎖已經被其他協程持有,那麼調用 lock() 的協程將會被掛起,直到鎖變為可用。
用法
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
val mutex = Mutex()
fun main() = runBlocking {
launch {
mutex.lock() // 獲取鎖
try {
// 保護的代碼段
println("Locked by coroutine 1")
delay(1000)
} finally {
mutex.unlock() // 確保釋放鎖
}
}
launch {
mutex.lock() // 等待並獲取鎖
try {
// 保護的代碼段
println("Locked by coroutine 2")
} finally {
mutex.unlock() // 確保釋放鎖
}
}
}
unlock:解鎖互斥鎖。
unlock() 方法用於釋放鎖,使得被掛起的其他協程可以繼續執行。如果 unlock() 被調用時沒有持有鎖,則會引發異常。
用法
如上面 lock() 示例中的 finally 塊所示。
tryLock
tryLock() 嘗試獲取鎖,如果鎖當前是可用的,則立即獲取鎖並返回 true;否則返回 false,且不會掛起當前協程。
用法
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
val mutex = Mutex()
fun main() = runBlocking {
launch {
if (mutex.tryLock()) { // 嘗試獲取鎖
try {
println("Lock acquired by coroutine 1")
delay(1000)
} finally {
mutex.unlock()
}
} else {
println("Coroutine 1: Lock not acquired")
}
}
launch {
if (mutex.tryLock()) { // 嘗試獲取鎖
try {
println("Lock acquired by coroutine 2")
} finally {
mutex.unlock()
}
} else {
println("Coroutine 2: Lock not acquired")
}
}
}
總結
lock():嘗試獲取鎖,如果鎖不可用,則掛起當前協程。unlock():釋放鎖,其他掛起的協程可以繼續執行。tryLock():嘗試獲取鎖,如果鎖不可用,則立即返回false,不會掛起當前協程。withLock():便捷方法,自動獲取和釋放鎖,確保在代碼塊執行後釋放鎖。
Mutex 的這些方法使得在 Kotlin 協程中進行線程安全的操作變得更加簡潔和直觀。根據實際需求選擇合適的方法,可以有效避免併發問題,提高代碼的健壯性和可維護性。
歡迎關注我的公眾號AntDream查看更多精彩文章!