基于redis 实现的分布式锁

第一版
在这里插入图片描述
实现逻辑和基本原理
逻辑:
1、每一次访问进来都先去获得redis 锁 如果获得到 则继续执行,如果获取不到 则直接返回
2、redis 的key 设有过期时间 避免某个请求处理不当(或方法执行到一半宕机或网络原因)导致 redis key 不能正确释放 死锁
3 在 finally 方法里进行手工释放锁
基本原理(即有什么样的理论基础 才可以用redis做分布式锁):
1、setIfAbsent 即 setnx 当key不存在时设置成功,当key 存在时会设置失败
2、redis设置key 和 设置过期时间 必须为原子性
否则在设置完key 后系统宕机 此时还没来得及设置过期时间 那么这个可以就成了永久的key了 就会产生死锁的情况
setIfAbsent 不是原子性的 (稍后讲解决方案)
问题
1、当这个方法执行时间大于10秒 此时 方法还没有执行完 key就自动过期了 此时 第二个请求就可以进来了 ,实际上是不应该进来的。
2、接 第一条 如果第二条请求还没执行完 第一条请求执行完了并释放了锁 ,此时第三条请求可以顺利进来 ,如此循环 这个锁就失效了。

第二方案:
在这里插入图片描述
解决上述第二个问题:
1、为每个请求生成一个uuid
2、如果第二条请求还没执行完 第一条请求执行完了 然后进行判断 如果当前锁是自己的进行释放,如果当前锁不是自己的就不释放,这样就 避免了锁失效。

第一个问题暂时还没解决*********************************

对于 setIfAbsent 不是原子性的问题 可以使用lua 脚本去实现。

https://blog.csdn.net/LYQ20010417/article/details/123468307

public Map<String,0bject> getRedisLock(){
Map<String,0bject> map = new HashMap<>() ;
String uuid = UuID.randomUuID() .tostring();
//1.占分布式锁的同时 给锁设置过期时间。
//这是一个原子性操作,要么同时成功,要么同时失败。
Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent( k: "lock",uuid, 30, TimeUnit.SECONDS);
//如果加锁成功
if (lock){
try
//执行业务逻辑map.put("msg","加锁成功");Jfinally {
//redis官网提供的解锁脚本,可实现 获取值和围除锁的操作是一个原子性操作
String script =
"if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
//2.使用函数执行副锁脚本
stringRedisTemplate,execute(new DefaultRedisScript<>(script,Long.class),Anrays.asList("lock"),uuid):
//加锁失败时,通过递归自旋重试。
else f
return this.getRedisLock() ;
return map;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于 Redis 实现分布式锁可以利用 Redis原子性操作和超时特性来实现。下面是一个基本的实现思路: 1. 获取锁:使用 RedisSETNX 命令,如果指定的锁 key 不存在,则设置该 key 的值为当前时间戳加上锁的超时时间,并返回成功;否则,返回失败。 2. 释放锁:使用 Redis 的 EVAL 命令,通过 Lua 脚本来实现原子性的删除锁。脚本的内容是先判断锁是否存在且超时,如果是则删除锁并返回成功;否则,返回失败。 下面是一个简单的 Python 代码示例: ```python import redis import time class RedisLock: def __init__(self, redis_client, lock_key, expire_time): self.redis = redis_client self.lock_key = lock_key self.expire_time = expire_time def acquire(self): while True: timestamp = int(time.time() * 1000) + self.expire_time acquired = self.redis.set(self.lock_key, timestamp, nx=True, px=self.expire_time) if acquired: return True time.sleep(0.001) def release(self): lua_script = """ if redis.call("exists", KEYS[1]) == 1 then local current_value = tonumber(redis.call("get", KEYS[1])) if current_value and current_value <= tonumber(ARGV[1]) then return redis.call("del", KEYS[1]) end end return 0 """ self.redis.eval(lua_script, 1, self.lock_key, int(time.time() * 1000) + self.expire_time) # 使用示例 redis_client = redis.Redis(host='localhost', port=6379, db=0) lock = RedisLock(redis_client, 'my_lock', 1000) # 锁的超时时间为 1000 毫秒 if lock.acquire(): try: # 执行需要加锁的代码 pass finally: lock.release() ``` 需要注意的是,以上代码仅是一个简单的实现示例,实际使用中还需要考虑异常处理、锁的可重入性、锁的可拥有时间等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值