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

集群环境下Redis读写多线程竞态条件无锁解决方案问询

解决方案

核心思路是利用Redis单线程执行命令的原子性,将「判断列表是否为空」和「写入初始值」两个操作合并为单个原子操作,完全规避竞态条件,无需加锁也不会产生线程阻塞。


方案1:原生LPUSH命令实现(无额外依赖)

Redis的LPUSH命令执行后会原子返回操作完成后列表的总长度,基于这个特性可以直接实现逻辑:

// 所有线程统一先执行写入操作
int currentListLen = lpush(key, value);
if (currentListLen > 1) {
    // 列表此前已有内容,当前线程写入的是冗余值,直接删除即可
    lpop(key);
    // 执行原if分支的业务逻辑
} else {
    // 当前线程是第一个写入的线程,执行原else分支的业务逻辑
}

优势

  • 完全基于Redis原生命令,不需要引入额外依赖,兼容性极强
  • 所有操作都是非阻塞的,调用后立即得到结果,不需要等待其他线程执行
  • 天然适配集群环境,单key操作不需要处理跨节点问题

方案2:Lua脚本实现(逻辑更直观)

如果希望逻辑更清晰,也可以把判断+写入逻辑封装为Lua脚本,Redis会以原子方式执行整个脚本,不会被其他请求打断:

-- 入参:KEYS[1]为列表key,ARGV[1]为要写入的初始值
local listLen = redis.call('LLEN', KEYS[1])
if listLen == 0 then
    redis.call('LPUSH', KEYS[1], ARGV[1])
    return 0 -- 标记:执行了写入操作,走原else分支
else
    return 1 -- 标记:列表已有内容,走原if分支
end

业务代码直接调用该Lua脚本,根据返回值执行对应分支逻辑即可。

优势

  • 逻辑直观易懂,后续维护成本低
  • 不需要额外处理冗余数据,写入操作只会执行一次

两种方案都不需要使用任何锁机制,也不依赖本地同步逻辑,完全满足集群环境的使用要求,也不会出现线程等待的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 01:15:03