【Kotlin 协程】协程并发安全问题 ( 使用 Atomic 并发安全类型 | 使用 Channel 通道 | 使用 Mutext 轻量级锁 | 使用 Semaphore 轻量级信号量 )
2023-09-14 09:07:26 时间
一、协程不安全数据访问
在多个线程中 同时访问 相同数据 , 就会出现 线程不安全 访问 的问题 ;
如果多个协程中 , 同时访问相同数据 , 同样会出现 不安全数据访问 问题 ;
协程不安全数据访问代码示例 : 同时开启 100000 个协程 , 对相同的 int 值进行累加 , 等所有协程访问完毕 , 查看最终结果 , 发现最终累加不足 100000 ;
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {
var count = 0
List(100000) {
GlobalScope.launch {
count++
}
}.joinAll()
println(count)
}
}
}
执行结果 :
15:30:41.957 System.out kim.hsl.coroutine I 99978
二、使用 Atomic 并发安全类型
使用 Atomic 原子类型数据 应对 协程不安全访问 问题 ;
代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.concurrent.atomic.AtomicInteger
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {
var count = AtomicInteger(0)
List(100000) {
GlobalScope.launch {
count.incrementAndGet()
}
}.joinAll()
println(count)
}
}
}
执行结果 :
15:57:02.984 System.out kim.hsl.coroutine I 100000
三、使用 Channel 通道
使用 Channel 通道进行协程间通信 , 该 Channel 通道是并发安全的 ;
参考如下博客 :
- 【Kotlin 协程】Channel 通道 ① ( Channel#send 发送数据 | Channel#receive 接收数据 )
- 【Kotlin 协程】Channel 通道 ② ( Channel 通道容量 | Channel 通道迭代 | 使用 iterator 迭代器进行迭代 | 使用 for in 循环进行迭代 )
- 【Kotlin 协程】Channel 通道 ③ ( CoroutineScope#produce 构造生产者协程 | CoroutineScope#actor 构造消费者协程 )
- 【Kotlin 协程】Channel 通道 ④ ( Channel 通道的热数据流属性 | Channel 通道关闭过程 | Channel 通道关闭代码示例 )
- 【Kotlin 协程】Channel 通道 ⑤ ( BroadcastChannel 广播通道 | 代码示例 )
四、使用 Mutext 轻量级锁
使用 Mutext 轻量级锁 , 加锁 Mutext#lock , 解锁 Mutext#unlock , 如果执行时获取不到 Mutext 锁 , 会挂起等待 Mutext 锁释放 , 不会阻塞线程 ;
首先 , 创建 Mutex 锁 实例对象 ;
val mutex = Mutex()
然后 , 将协程中的并发代码定义在 mutex.withLock
代码块内 ;
GlobalScope.launch {
mutex.withLock {
count++
}
}
代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.util.concurrent.atomic.AtomicInteger
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {
var count = 0
val mutex = Mutex()
List(100000) {
GlobalScope.launch {
mutex.withLock {
count++
}
}
}.joinAll()
println(count)
}
}
}
执行结果 :
15:57:02.984 System.out kim.hsl.coroutine I 100000
五、使用 Semaphore 轻量级信号量
使用 Semaphore 轻量级信号量 , 可以同时定义多个 信号量 , 协程获取到 对应 信号量时才能执行并发任务 ;
首先 , 创建 Semaphore 信号量 实例对象 ;
val semaphore = Semaphore(1)
然后 , 将协程中的并发代码定义在 semaphore.withPermit
代码块内 ;
GlobalScope.launch {
semaphore.withPermit {
count++
}
}
代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {
var count = 0
val semaphore = Semaphore(1)
List(100000) {
GlobalScope.launch {
semaphore.withPermit {
count++
}
}
}.joinAll()
println(count)
}
}
}
执行结果 :
19:10:54.612 System.out kim.hsl.coroutine I 100000
相关文章
- [Kotlin] Array List ArrayList
- Kotlin 朱涛-23 协程 异常 try-catch Exception
- 熬夜再战Android之修炼Kotlin-【Kotlin的static是什么】
- Android kotlin 系列讲解(基础篇) 关键字:lateinit和by lazy
- JVM语言生态结构原理图 从Java,Kotlin,Scala,Groovy等语言的编译、执行全过程图示解析...
- 现代编程语言: Kotlin 之美 - 当下最火的编程语言欣赏
- Kotlin 并发编程之"协程"
- 《Kotlin极简教程》第六章 Kotlin函数式编程(FP)
- 【Kotlin 协程】协程中的多路复用技术 ② ( select 函数原型 | SelectClauseN 事件 | 查看挂起函数是否支持 select )
- 【Kotlin 协程】协程底层实现 ④ ( 结构化并发 | viewModelScope 作用域示例 )
- 简单几招提速 Kotlin Kapt编译
- Kotlin 喧嚣过后,谈谈 Java 程序员未来的出路
- Kotlin 实现粘列表标题+ListView的功能