线程安全的协程集合管理
【代码】线程安全的协程集合管理。
·
示例:网络请求管理器
import kotlinx.coroutines.*
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.CopyOnWriteArrayList
class NetworkRequestManager {
// 原子引用:线程安全地存储当前准备发送的请求ID
private val mReadyRequestId by lazy { AtomicReference<String>() }
// 线程安全的集合:存储所有活跃的网络请求Job
private val mRequestJobs by lazy { CopyOnWriteArrayList<Job>() }
// 扩展函数:跟踪Job到集合中
fun Job.trackRequestJob(requestId: String): Job {
mReadyRequestId.set(requestId) // 设置当前请求ID
mRequestJobs.add(this) // 添加到集合
invokeOnCompletion { job ->
mRequestJobs.remove(this) // Job完成后从集合移除
if (isCompletedConnectJobs()) {
mReadyRequestId.set(null) // 所有请求完成后清理ID
}
}
return this
}
// 判断所有请求是否完成
fun isCompletedRequestJobs(): Boolean {
return mRequestJobs.isEmpty() || mRequestJobs.all { it.isCompleted }
}
// 模拟发起网络请求
suspend fun sendRequest(requestId: String) {
val job = GlobalScope.launch {
// 模拟网络请求
delay(1000)
println("Request $requestId completed")
}
job.trackRequestJob(requestId) // 跟踪Job
}
}
// 使用示例
fun main() = runBlocking {
val manager = NetworkRequestManager()
manager.sendRequest("req1")
manager.sendRequest("req2")
while (!manager.isCompletedRequestJobs()) {
delay(100)
}
println("All requests completed")
}
1. 线程安全的集合使用(CopyOnWriteArrayList)
- 问题:在多线程环境下,如果多个协程同时添加或移除 Job,普通 ArrayList 会抛出
ConcurrentModificationException。 - 解决方案:使用
CopyOnWriteArrayList,它在写入时复制底层数组,读操作无需加锁,适合读多写少的场景。 - 代码体现:
private val mRequestJobs by lazy { CopyOnWriteArrayList<Job>() }
- 实际意义:确保
mRequestJobs的操作(如add、remove)在多线程环境下是安全的。
2. 原子引用(AtomicReference)的应用
- 问题:如果多个线程同时修改
mReadyRequestId,可能导致数据不一致。 - 解决方案:使用
AtomicReference,通过原子操作保证状态修改的线程安全。 - 代码体现:
private val mReadyRequestId by lazy { AtomicReference<String>() }
- 实际意义:确保
mReadyRequestId的读写操作是原子的,避免竞态条件。
3. 协程生命周期管理(Job.invokeOnCompletion)
- 问题:需要知道每个网络请求协程何时完成,以便清理资源。
- 解决方案:通过
invokeOnCompletion监听 Job 的完成事件,并在完成后从集合中移除。 - 代码体现:
invokeOnCompletion { job ->
mRequestJobs.remove(this)
if (isCompletedRequestJobs()) {
mReadyRequestId.set(null)
}
}
- 实际意义:自动清理已完成任务的 Job,避免内存泄漏。
4. 集合状态统一判断(isCompletedRequestJobs)
- 问题:需要统一判断所有网络请求是否完成。
- 解决方案:通过检查集合是否为空或所有 Job 是否完成,返回整体状态。
- 代码体现:
fun isCompletedRequestJobs(): Boolean {
return mRequestJobs.isEmpty() || mRequestJobs.all { it.isCompleted }
}
- 实际意义:提供一种高效的方式来统一管理多个任务的状态。
5. 扩展函数封装(Job.trackRequestJob)
- 问题:重复编写 Job 的跟踪逻辑(如添加到集合、监听完成事件)。
- 解决方案:通过扩展函数封装逻辑,提升代码复用性。
- 代码体现:
fun Job.trackRequestJob(requestId: String): Job {
// ...逻辑
}
- 实际意义:减少重复代码,提高开发效率。
更多推荐



所有评论(0)