题目
设计一个基于协程的并发安全缓存系统
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
协程并发控制,状态管理,异常处理,性能优化
快速回答
实现要点:
- 使用
Mutex保护共享状态避免竞态条件 - 通过
async启动并发任务并缓存Deferred对象 - 实现缓存击穿防护:相同 key 的请求共享同一异步结果
- 添加 TTL 机制和后台刷新逻辑
- 使用
SupervisorJob隔离异常避免全局崩溃 - 通过
CoroutineStart.LAZY延迟计算优化资源
问题场景
在高并发系统中,需要实现一个线程安全的缓存,要求:1) 支持并发读写 2) 防止缓存击穿(大量并发请求穿透缓存)3) 支持 TTL 自动刷新 4) 异常隔离不影响整体服务。
核心实现方案
class CoroutineCache {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private val mutex = Mutex()
private val cache = mutableMapOf<String, Any>()
private val deferredMap = mutableMapOf<String, Deferred<Any>>()
suspend fun <T : Any> compute(
key: String,
ttl: Duration = Duration.INFINITE,
block: suspend () -> T
): T {
// 1. 检查缓存有效性
val cached = mutex.withLock { cache[key] }
if (cached != null && !isExpired(key, ttl)) {
@Suppress("UNCHECKED_CAST")
return cached as T
}
// 2. 防止缓存击穿
return mutex.withLock {
// 双重检查锁定模式
deferredMap[key]?.let { existing ->
return@withLock existing.await() as T
}
// 3. 创建新异步任务
val newDeferred = scope.async(start = CoroutineStart.LAZY) {
try {
block().also { result ->
mutex.withLock {
cache[key] = result as Any
deferredMap.remove(key)
}
}
} catch (e: Exception) {
mutex.withLock { deferredMap.remove(key) }
throw e
}
}
deferredMap[key] = newDeferred
newDeferred.start() // 显式启动避免重复计算
newDeferred.await() as T
}
}
private fun isExpired(key: String, ttl: Duration): Boolean {
// 实现基于时间的过期检查(伪代码)
return ttl != Duration.INFINITE && (currentTime - cacheTime[key]) > ttl
}
}原理说明
- 并发控制:
Mutex保护cache和deferredMap的读写操作,避免竞态条件 - 缓存击穿防护:相同 key 的并发请求共享同一个
Deferred对象,仅首次实际执行计算 - 异常隔离:
SupervisorJob确保单个任务失败不影响其他操作 - 性能优化:
CoroutineStart.LAZY延迟启动协程,避免不必要的计算
最佳实践
- 使用
Dispatchers.IO替代Dispatchers.Default处理阻塞 I/O 操作 - 添加缓存淘汰策略(如 LRU)防止内存溢出
- 实现
refreshAsync方法后台异步刷新热门数据 - 监控缓存命中率和延迟指标
常见错误
- 死锁风险:在
mutex.withLock内部调用挂起函数(需确保临界区内无挂起) - 内存泄漏:未清理
deferredMap导致对象无法回收 - 协程泄露:未使用
SupervisorJob导致异常传播使整个 scope 取消 - 类型安全:未正确处理泛型类型转换(示例中使用
@Suppress需谨慎)
扩展知识
- 缓存雪崩防护:为不同 key 添加随机过期时间偏移量
- 响应式扩展:使用
Flow实现缓存更新事件流 - 分布式场景:结合 Redis 等外部存储实现多节点一致性
- Structured Concurrency:通过
coroutineScope子作用域管理生命周期