You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin协程代码中async块未持有Mutex的含义、原因及意义是什么

Kotlin CacheOnSuccess.kt 代码问题解答

注释的具体含义

该注释明确说明:async代码块内部执行block()时,之前通过mutex.withLock获取的互斥锁已经被释放,这段异步执行的逻辑不会持有Mutex锁。

为什么async块中不会持有mutex

协程Mutex的withLock方法自带自动释放逻辑:进入withLock代码块前会自动加锁,只要离开代码块(不管是正常返回还是抛出异常)就会自动解锁。
代码中async { }只是在withLock代码块内部创建了一个异步任务,不会等待异步任务执行完成,withLock代码块拿到async返回的Deferred实例后就直接退出,锁也随之释放。等后续调度执行async内部的block()时,锁已经被释放很久,自然不会持有mutex。
补充说明:给deferred赋值的also代码块是在withLock内部执行的,此时仍然持有锁,符合代码开头注释「所有deferred的读写操作都要持有锁保证线程安全」的要求。

这一设计的意义

  • 提升并发性能:block()通常是耗时操作(例如网络请求、数据库查询、 heavy计算),如果持有锁直到block()执行完才释放,这段时间所有调用getOrAwait()的协程都会被阻塞在抢锁步骤,完全无法并发,性能损失极大。该设计只把锁的持有范围限制在「检查deferred是否存在、创建新Deferred、赋值deferred」这几个极快的操作上,锁粒度极小,并发性能更高。
  • 避免死锁风险:如果block()内部存在其他加锁逻辑,长时间持有锁很容易出现不同协程交叉持有锁的死锁问题,锁早释放可以规避这类风险。
  • 不影响功能正确性:加锁的核心目的只是保证「同一时间只有一个协程能创建Deferred实例,避免多个协程重复执行block()」,只要创建Deferred和赋值deferred的操作在锁保护下完成即可。后续其他协程调用getOrAwait()抢锁时,会读到已经存在的deferred,直接返回同一个实例等待结果,不会重复触发block()执行,功能完全符合预期。

内容的提问来源于stack exchange,提问作者VIN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:42:00