基于redis的分布式锁实现方案--redisson

实例代码地址,请前往:https://gitee.com/GuoqingLee/distributed-seckill

redis官方文档地址,请前往:http://www.redis.cn/topics/distlock.html

前言

关于分布式锁的实现,目前主流方案有以下三类:

1、基于数据库的乐观锁;

2、基于redis实现的锁服务;

3、基于zookeeper的实现;

网上关于怎么实现redis的分布式锁,一搜一大把的文章,有写的比较好的,也有明显存在缺陷的,非常容易误导初入这一块的初学者;

而存在的问题,无外乎是setnx()-->expire(),保证不了原子性,容易出现死锁等情况,这里就不在去做解释了;

本文的主旨是如何使用redis官方推荐的redisson实现redis的分布式锁;

一、具体实现:

maven引入需要的jar

1 <dependency>
2     <groupId>org.redisson</groupId>
3     <artifactId>redisson-spring-boot-starter</artifactId>
4     <version>3.10.1</version>
5 </dependency>

配置文件如下

# common spring boot settings

spring.redis.database=
spring.redis.host=
spring.redis.port=
spring.redis.password=
spring.redis.ssl=
spring.redis.timeout=
spring.redis.cluster.nodes=
spring.redis.sentinel.master=
spring.redis.sentinel.nodes=

封装工具类:

  1 package cn.com.bluemoon.redis.lock;
  2 
  3 import java.util.concurrent.TimeUnit;
  4 
  5 import org.redisson.api.RLock;
  6 import org.redisson.api.RedissonClient;
  7 import org.springframework.beans.factory.annotation.Autowired;
  8 import org.springframework.stereotype.Component;
  9 
 10 /**
 11  * 基于Redisson的分布式锁实现
 12  * @author Guoqing.Lee
 13  * @date 2019年1月23日 下午4:04:57
 14  *
 15  */
 16 @Component
 17 public class RedissonDistributedLocker {
 18     
 19     @Autowired
 20     private RedissonClient redissonClient;
 21     
 22     /**
 23      * 加锁
 24      * @param lockKey
 25      * @return
 26      */
 27     public RLock lock(String lockKey) {
 28         RLock lock = redissonClient.getLock(lockKey);
 29         lock.lock();
 30         return lock;
 31     }
 32     
 33     /**
 34      * 加锁,过期自动释放
 35      * @param lockKey
 36      * @param leaseTime    自动释放锁时间
 37      * @return
 38      */
 39     public RLock lock(String lockKey, long leaseTime) {
 40         RLock lock = redissonClient.getLock(lockKey);
 41         lock.lock(leaseTime, TimeUnit.SECONDS);
 42         return lock;
 43     }
 44     
 45     /**
 46      * 加锁,过期自动释放,时间单位传入
 47      * @param lockKey
 48      * @param unit        时间单位
 49      * @param leaseTime    上锁后自动释放时间
 50      * @return
 51      */
 52     public RLock lock(String lockKey, TimeUnit unit, long leaseTime) {
 53         RLock lock = redissonClient.getLock(lockKey);
 54         lock.lock(leaseTime, unit);
 55         return lock;
 56     }
 57     
 58     /**
 59      * 尝试获取所
 60      * @param lockKey
 61      * @param unit        时间单位
 62      * @param waitTime    最多等待时间
 63      * @param leaseTime    上锁后自动释放时间
 64      * @return
 65      */
 66     public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
 67         RLock lock = redissonClient.getLock(lockKey);
 68         try {
 69             return lock.tryLock(waitTime, leaseTime, unit);
 70         } catch (InterruptedException e) {
 71             return false;
 72         }
 73     }
 74     
 75     /**
 76      * 尝试获取所
 77      * @param lockKey
 78      * @param waitTime    最多等待时间
 79      * @param leaseTime    上锁后自动释放锁时间
 80      * @return
 81      */
 82     public boolean tryLock(String lockKey, long waitTime, long leaseTime) {
 83         RLock lock = redissonClient.getLock(lockKey);
 84         try {
 85             return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
 86         } catch (InterruptedException e) {
 87             return false;
 88         }
 89     }
 90     
 91     /**
 92      * 释放锁
 93      * @param lockKey
 94      */
 95     public void unlock(String lockKey) {
 96         RLock lock = redissonClient.getLock(lockKey);
 97         lock.unlock();
 98     }
 99     
100     /**
101      * 释放锁
102      * @param lock
103      */
104     public void unlock(RLock lock) {
105         lock.unlock();
106     }
107     
108 }

二、使用方式

方式一:

 1     @Autowired
 2     private RedissonDistributedLocker redissonDistributedLocker;
 3 
 4         String lockKey = "BM_MARKET_SECKILL_" + stallActivityId;
 5     try {
 6                 //超过2S自动释放锁
 7         redissonDistributedLocker.lock(lockKey, 2L);
 8                 //业务处理
 9 
10         } finally {
11         redissonDistributedLocker.unlock(lockKey);  //释放锁
12     }    

方案二:

 1 @Autowired
 2 private RedissonDistributedLocker redissonDistributedLocker;
 3 
 4 public void test() throws InterruptedException {
 5     final int[] counter = {0};
 6 
 7         for (int i= 0; i < 100; i++){
 8         
 9             new Thread(new Runnable() {
10 
11                 @Override
12 
13                 public void run() {
14                     boolean isGetLock = redissonDistributedLocker.tryLock("test0001", 3L, 1L);
15                     if(isGetLock) {
16                         try {
17                             int a = counter[0];
18                             counter[0] = a + 1;
19                             logger.info(a + "");
20                         } finally {
21                             redissonDistributedLocker.unlock("test0001");
22                         }
23                     }
24                 }
25             }).start();
26             
27         }
28 
29         // 主线程休眠,等待结果
30         Thread.sleep(5000);
31         System.out.println(counter[0]);
32         logger.info(counter[0] + "");
33 }

闲话就不多说了,希望能对你有所帮助。

 

转载于:https://www.cnblogs.com/ocean-sky/p/10320627.html

### Redis 分布式锁Redisson实现原理 #### 1. **Redis 分布式锁** Redis 分布式锁的核心思想是通过 `SETNX` 和 `EXPIRE` 来实现加锁操作。在早期版本(Redis 2.6.12之前),由于 `SETNX` 不支持设置过期时间,因此需要分两步完成:先调用 `SETNX` 创建键值对表示锁定状态,再调用 `EXPIRE` 设置过期时间以防止死锁[^3]。 然而这种两步操作无法保证原子性,可能会因网络延迟或其他异常导致锁未成功创建却设置了过期时间。为此,Redis 2.6.12引入了新的命令 `SET key value NX PX milliseconds`,其中 `NX` 表示只有当键不存在时才执行设置操作,`PX` 则用于指定毫秒级的过期时间。这种方式能够在一个命令内完成加锁并设定超时,从而有效解决了上述问题。 #### 2. **Redisson 实现分布式锁** Redisson 是基于 Redis 开发的一个 Java 客户端库,它不仅实现了更高级别的抽象接口,还提供了多种类型的分布式对象和服务功能。对于分布式锁而言,Redisson 提供了一种更加健壮可靠的解决方案——`RLock` 接口及其子类实例化方式。 - **加锁逻辑** Redisson 使用 Lua 脚本来确保整个加锁过程具有原子性。该脚本会检查目标资源是否已被占用;如果未被占用,则尝试获取锁并将当前线程 ID 记录下来作为持有者的唯一标识符[^1]。 - **续命机制** 当某个客户端成功获得锁之后,Redisson 会在后台启动一个定时器任务定期向服务器发送续约请求延长锁的有效期限,直到显式解锁为止。此设计可以避免因长时间运行的任务而导致锁提前失效的情况发生[^2]。 - **自旋重试策略** 如果初次未能取得所需资源,则按照预定义间隔不断重复尝试直至达到最大等待时限或最终放弃争夺控制权。 - **公平性和可靠性保障措施** 在某些特殊情况下(比如网络分区), 可能会出现部分节点认为自己已经拿到了全局唯一的锁,但实际上其他地方也有竞争者存在的情形下, redisson 还特别考虑到了这一点并通过内部复杂的协调算法尽可能减少冲突概率[^4]. #### 性能对比分析 | 特性 | Redis 原生分布锁 | Redisson | |-------------------------|------------------------------------------|----------------------------------| | 加锁效率 | 较高 | 略低 | | 锁安全性 | 存在网络抖动等问题 | 更安全可靠 | | 功能扩展能力 | 单纯提供基础加解鎖功能 | 支持更多特性如自动续租、可重入等 | | 易用程度 | 需要开发者手动处理很多细节 | API 封装良好易于集成 | 从表中可以看出虽然原生态方法简单高效但在实际应用过程中往往面临诸多挑战;而借助第三方工具包则可以在一定程度上弥补这些不足之处. ```java // 示例代码展示如何利用Redisson进行分布式锁管理 import org.redisson.api.RLock; import org.redisson.api.RedissonClient; public class DistributedLockExample { private final RedissonClient redissonClient; public void acquireAndReleaseLock(String lockName) throws InterruptedException{ RLock lock = redissonClient.getLock(lockName); try { boolean isLocked = lock.tryLock(10, TimeUnit.SECONDS); // 尝试获取锁最长等待时间为10秒 if(isLocked){ System.out.println(Thread.currentThread().getName()+" acquired the lock."); Thread.sleep(5000L); // Simulate some work }else{ System.err.println("Failed to get lock after waiting..."); } } finally { if(lock.isHeldByCurrentThread()){ lock.unlock(); System.out.println(Thread.currentThread().getName()+ " released the lock."); } } } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值