redis分布式锁的简单实现

4 篇文章 0 订阅

在我的上一篇博客 stringRedisTemplate实现分布式锁中,由于没有考虑到原子性的问题,所以这篇博客将简单版的分布式锁实现出来.

还是老样子,学习一个技术分三步 是什么? 怎么用? 为什么?.

1 什么是分布式锁?

在单机应用下的并发编程中,我们通过锁(synchronized 、Lock),来避免由于竞争而造成的数据不一致问题。而分布式锁,就是为了解决分布式应用中的数据不一致问题.通常使用redis分布式锁.

分布式锁的可靠性

为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

  1. 互斥性。在任意时刻,只有一个客户端能持有锁。
  2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  3. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  4. 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

 

2 redis分布式锁怎么用?

加锁

加锁方法需要传递四个参数(redis对象 ,key值 ,请求者id ,过期时间)

  public static boolean addLock(Jedis jedis, String key, String requestId, int expireTime ){
        //判断值是否为null 或者空
        if("".equals(key)||"".equals(requestId)||null==requestId||null==key){
            return false;
        }
        //判断过期时间是否合法
        if(0>expireTime){
            return false;
        }
        //加锁
        String result=jedis.set(key,requestId,"NX","PX",expireTime);
        if("ok".equals(result)){
            return true;
        }
        return  false;
    }

参数解释:

1:redis就不用说了,处理锁用的

2:key值,用来保证唯一性

3:请求者id:  这个requestId 是用来保证 解铃还须系铃人这个特性的.加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

4:第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;

5:第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。

6: 过期时间

解锁

解锁方法有三个参数(redis对象,key值,请求者id)

//常量用来判断是否解锁成功
    private static final Long RELEASE_SUCCESS = 1L;

    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
        //Lua脚本代码
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        //解锁
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

解释:

参数和加锁的一样,就不说了.

这里需要说的是lua脚本

Lua脚本代码,我们写了一个简单的Lua脚本代码, 首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。那么为什么要使用Lua语言来实现呢?因为要确保上述操作是原子性的。

eval代码,我们将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。eval()方法是将Lua代码交给Redis服务端执行。那么为什么执行eval()方法可以确保原子性? 简单来说,就是在eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval命令执行完成,Redis才会执行其他命令。

 

到这里redis分布式锁就完成了. 感谢老哥的指正.

参考网址:https://blog.csdn.net/yb223731/article/details/90349502

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值