并发控制:Mutex 与 Semaphore
在协程世界中,传统的 synchronized 和 ReentrantLock 会阻塞线程,严禁使用。Kotlin 提供了非阻塞的替代方案。
互斥锁:Mutex
Mutex (Mutual Exclusion) 是异步的锁。
核心特性
- 非阻塞: 当获取不到锁时,协程挂起(释放线程),等待锁释放后恢复。
- 不可重入 (Non-reentrant): 这是与
synchronized最大的不同。同一个协程不能连续两次加锁,否则会死锁。
kotlin
val mutex = Mutex()
suspend fun safeUpdate() {
// 自动加锁,执行完自动释放 (即使抛异常)
mutex.withLock {
// 临界区逻辑
sharedData++
}
}死锁陷阱
kotlin
mutex.withLock {
// ❌ 错误:Mutex 不可重入!这里会永久挂起。
mutex.withLock { ... }
}信号量:Semaphore
用于限制同时访问某些资源(如数据库连接、网络请求)的并发数量。
kotlin
val semaphore = Semaphore(3) // 允许 3 个并发
repeat(100) {
launch {
semaphore.withPermit {
// 同一时刻最多只有 3 个协程在运行此块代码
download()
}
}
}替代 Actor:Channel 状态机
早期的 actor 构建器已被废弃。现在推荐使用 Channel 来实现无锁的并发状态管理(CSP 模型)。
原理:将状态限制在单个协程内,通过 Channel 接收命令来修改状态。
kotlin
sealed class Msg
class Add(val value: Int) : Msg()
class Get(val resp: CompletableDeferred<Int>) : Msg()
fun CoroutineScope.counterActor() = launch {
var counter = 0 // 状态被封闭在局部变量,天然线程安全
val channel = Channel<Msg>()
// 消费逻辑
for (msg in channel) {
when (msg) {
is Add -> counter += msg.value
is Get -> msg.resp.complete(counter)
}
}
}