
golang 利用redis实现分布式锁
发布日期:2021-05-10 23:13:06
浏览次数:25
分类:精选文章
本文共 3168 字,大约阅读时间需要 10 分钟。
Redis知识准备
Redis SETNX命令
SETNX命令用于在Redis中设置或修改字符串值。如果key不存在,则创建key,并将值设为指定字符串,返回true。如果key已存在,则不修改值,返回false。
Redis TTL命令
TTL命令用于获取key的过期时间。如果key设置了过期时间,则返回key到过期时所剩余的时间。如果key未设置过期时间,则返回-1。
代码示例
Redis连接配置
package mainimport ( "fmt" "github.com/go-redis/redis" "time")
单节点Redis客户端连接
func connRedisSingle(addr, password string) *redis.Client { conf := redis.Options{ Addr: addr, Password: password, } return redis.NewClient(&conf)}
Redis集群客户端连接
func connRedisCluster(address []string, password string) *redis.ClusterClient { conf := redis.ClusterOptions{ Addrs: address, Password: password, } return redis.NewClusterClient(&conf)}
锁的实现
加锁逻辑
func (r *redisClient) lock(value string) (error, bool) { ret := r.SetNX("hello", value, time.Second*10) if err := ret.Err(); err != nil { fmt.Printf("set value %s error: %v\n", value, err) return err, false } return nil, ret.Val()}
解锁逻辑
func (r *redisClient) unlock() bool { ret := r.Del("hello") if err := ret.Err(); err != nil { fmt.Println("unlock error: ", err) return false } return true}
优化锁获取逻辑
func (r *redisClient) retryLock() bool { ok := false for !ok { err, t := r.getTTL() if err != nil { return false } if t > 0 { fmt.Printf("锁被抢占, %f 秒后重试...\n", (t / 10).Seconds()) time.Sleep(t / 10) } err, ok = r.lock("Jan") if err != nil { return false } } return ok}
获取锁的过期时间
func (r *redisClient) getTTL() (error, time.Duration) { ret := r.TTL("hello") if err := ret.Err(); err != nil { fmt.Println("get TTL error: ", err) return err, 0 } return nil, ret.Val()}
多线程锁获取逻辑
func (r *redisClient) threadLock(threadId string) { for { err, _ := r.getLock() if err != nil && err.Error() == "redis: nil" { fmt.Printf("线程 %s 开始加锁\n", threadId) err, ok := r.lock("Jan") if err != nil { return } if !ok { if !r.retryLock() { fmt.Printf("线程 %s 加锁失败\n", threadId) return } } fmt.Printf("线程 %s 已加锁\n", threadId) time.Sleep(5 * time.Second) r.unlock() fmt.Printf("线程 %s 已释放锁\n", threadId) return } else if err != nil { return } err, t := r.getTTL() if err != nil { return } if t > 0 { fmt.Printf("线程 %s 锁被占用, %f 秒后重试\n", threadId, (t/10).Seconds()) time.Sleep(t/10) } }}
运行主程序
func main() { var r redisClient address := "192.168.1.151:6379" cl := connRedisSingle(address, "") defer cl.Close() r = redisClient(*cl) // 线程1获取锁 go r.threadLock("1") //time.Sleep(10 * time.Millisecond) // 线程2获取锁 go r.threadLock("2") select {}}
Redis锁实现总结
通过上述代码示例,可以实现一个基于Redis的锁机制。代码中使用了SETNX命令来尝试加锁,如果失败则通过获取锁的过期时间和重试机制来重新获取锁。在多线程环境下,通过检查锁的状态和过期时间,实现了锁的可重入和优化。
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2025年04月24日 11时43分01秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
kuangbin带你飞 KMP & 扩展KMP & Manacher总结(一)
2019-03-15
PhotoshopCC2019制作表情包
2019-03-15
超好用的原生 JS + Canvas 进行图片压缩
2019-03-15
node 环境使用七牛云完成文件的上传下载与管理
2019-03-15
Android简单MVP解析接口列表,搜索框,点击切换
2019-03-15
ADB
2019-03-15
响应的HTTP协议格式+常见的响应码
2019-03-15
Java数组
2019-03-15
创建线程方式
2019-03-15
线程池
2019-03-15
Netty读写方法
2019-03-15
LRUCache
2019-03-15
Mac上如何强制关闭应用
2019-03-15
关于Linux系统中touch命令的说明
2019-03-15
剑指Offer03-数组中重复的数字
2019-03-15
将windows里的内容直接复制粘贴到ubuntu,提高效率
2019-03-15
将tomcat设置成window自启动服务
2019-03-15
17蓝桥试题之承压计算
2019-03-15
webservice 远程服务器返回错误:(400)错误的请求
2019-03-15
给JS对象添加扩展方法
2019-03-15