redis 实现分布式锁的

文章讲述了如何使用Redisson库处理分布式锁的原子性、超时、重入、主从一致性等问题,并提出通过AOP和简单工厂模式简化锁操作,提供不同类型的锁和失败策略的选择。
摘要由CSDN通过智能技术生成

1:使用 set key value ex nx 命令

nx:Redis 会先检查指定的 key 是否已经存在,如果不存在则使用 SETNX 命令为其设置新值。这个过程是原子性的,可以保证在并发环境下同一时刻只有一个客户端能够成功地为一个 key 设定值。

ex:可以为key设置一个过期时间,到了规定时间,这个锁就会自动失效

  • 锁的重入问题:同一个线程多次获取锁的场景,目前不支持,可能会导致死锁

  • 锁失败的重试问题:获取锁失败后要不要重试?目前是直接失败,不支持重试

  • Redis主从的一致性问题:由于主从同步存在延迟,当线程在主节点获取锁后,从节点可能未同步锁信息。如果此时主宕机,会出现锁失效情况。此时会有其它线程也获取锁成功。从而出现并发安全问题。

  • ...

当然,上述问题并非无法解决,只不过会比较麻烦。例如:

  • 原子性问题:可以利用Redis的LUA脚本来编写锁操作,确保原子性

  • 超时问题:利用WatchDog(看门狗)机制,获取锁成功时开启一个定时任务,在锁到期前自动续期,避免超时释放。而当服务宕机后,WatchDog跟着停止运行,不会导致死锁。

  • 锁重入问题:可以模拟Synchronized原理,放弃setnx,而是利用Redis的Hash结构来记录锁的持有者以及重入次数,获取锁时重入次数+1,释放锁是重入次数-1,次数为0则锁删除

  • 主从一致性问题:可以利用Redis官网推荐的RedLock机制来解决

因此,我们只要会使用Redisson,即可解决上述问题,无需自己动手编码了

2 .redisson

1.引入redisson 依赖

2.配置连接redis

3.

利用Redisson获取锁时可以传3个参数:

  • waitTime:获取锁的等待时间。当获取锁失败后可以多次重试,直到waitTime时间耗尽。waitTime默认-1,即失败后立刻返回,不重试。

  • leaseTime:锁超时释放时间。默认是30,同时会利用WatchDog来不断更新超时时间。需要注意的是,如果手动设置leaseTime值,会导致WatchDog失效。

  • TimeUnit:时间单位

Redisson的分布式锁使用并不复杂,基本步骤包括:

  • 1)创建锁对象

  • 2)尝试获取锁

  • 3)处理业务

  • 4)释放锁

但是,除了第3步以外,其它都是非业务代码,对业务的侵入较多:非业务代码格式固定,每次获取锁总是在重复编码。我们可不可以对这部分代码进行抽取和简化,业务前、后都是固定的锁操作。既然如此,我们完全可以基于AOP的思想,将业务部分作为切入点,将业务前后的锁操作作为环绕增强

注解本身起到标记作用,同时还要带上锁参数:

  • 锁名称

  • 锁等待时间

  • 锁超时时间

  • 时间单位

锁的类型虽然有多种,但类型是有限的几种,完全可以通过枚举定义出来。然后把这个枚举作为MyLock注解的参数,交给用户去选择自己要用的类型。这里我们的需求是根据用户选择的锁类型,创建不同的锁对象。有一种设计模式刚好可以解决这个问题:简单工厂模式

1.我们首先定义一个锁类型枚举:

2.然后在自定义注解中添加锁类型这个参数:

3.然后定义一个锁工厂,用于根据锁类型创建锁对象:

4.我们将锁对象工厂注入MyLockAspect,然后就可以利用工厂来获取锁对象了:

此时,在业务中,就能通过注解来指定自己要用的锁类型了

多线程争抢锁,大部分线程会获取锁失败,而失败后的处理方案和策略是多种多样的。目前,我们获取锁失败后就是直接抛出异常,没有其它策略,这与实际需求不一定相符。

大的方面来说,获取锁失败要从两方面来考虑:

  • 获取锁失败是否要重试?有三种策略:

    • 不重试,对应API:lock.tryLock(0, 10, SECONDS),也就是waitTime小于等于0

    • 有限次数重试:对应API:lock.tryLock(5, 10, SECONDS),也就是waitTime大于0,重试一定waitTime时间后结束

    • 无限重试:对应API lock.lock(10, SECONDS) , lock就是无限重试

  • 重试失败后怎么处理?有两种策略:

    • 直接结束

    • 抛出异常

策略模式。同时,我们还需要定义一个失败策略的枚举。在MyLock注解中定义这个枚举类型的参数,供用户选择。然后,在MyLock注解中添加枚举参数:最后,修改切面代码,基于用户选择的策略来处理:这个时候,我们就可以在使用锁的时候自由选择锁类型、锁策略了:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值