(1)不安全的并發(fā)訪問
我們使用線程在解決并發(fā)問題的時候總是會遇到線程安全的問題,而Java平臺上的Kotlin協(xié)程實現(xiàn)免不了存在并發(fā)調(diào)度的情況,因此線程安全同樣值得留意。
runBlocking {
var count = 0
List(1000) {
GlobalScope.launch { count++ }
}.joinAll()
println(count)
}
打印出來的count值并不是1000。
(2)協(xié)程并發(fā)安全
在Java中,提供了原子性的對象:AtomicInteger,可以保證協(xié)程的安全性:
runBlocking {
var count = AtomicInteger(0)
List(1000) {
GlobalScope.launch { count.incrementAndGet()}
}.joinAll()
println(count)
}
除了我們在線程中常用的解決并發(fā)問題的手段之外,協(xié)程框架也提供了一些并發(fā)安全工具,包括:
- Channel:并發(fā)安全的消息通道;
- Mutex:輕量級鎖,它的lock和unlock從語義上與線程鎖比較類似,之所以輕量級是因為它在獲取不到鎖時不會阻塞線程,二十掛起等待鎖的釋放。
- Semaphore:輕量級信號量,信號量可以有多個,協(xié)程在獲取到信號量后即可執(zhí)行并發(fā)操作。當(dāng)Semaphore的參數(shù)為1時,效果等價于Mutext。
Mutex演示:
runBlocking {
var count = 0
val mutex = Mutex()
List(1000) {
GlobalScope.launch {
mutex.withLock { count++ }
}
}.joinAll()
println(count)
}
Semaphore演示:
runBlocking {
var count = 0
val semaphore = Semaphore(1)
List(1000) {
GlobalScope.launch {
semaphore.withPermit { count++ }
}
}.joinAll()
println(count)
}
(3)避免訪問外部可變狀態(tài)
編寫函數(shù)時要求它不得訪問外部狀態(tài),只能基于參數(shù)做運算,通過返回值提供運算結(jié)果。
runBlocking {
var count = 0
var result = count + List(1000) {
GlobalScope.async { 1 }
}.map { it.await() }.sum()
println(result)
}
[完...]