Springboot基于Redisson如何实现Redis分布式可重入锁源码解析
Springboot基于Redisson如何实现Redis分布式可重入锁源码解析
这篇文章主要介绍了Springboot基于Redisson如何实现Redis分布式可重入锁源码解析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
一、前言
我们在实现使用Redis实现分布式锁,最开始一般使用SET resource-name anystring NX EX max-lock-time
进行加锁,使用Lua脚本保证原子性进行实现释放锁。这样手动实现比较麻烦,对此Redis官网也明确说Java版使用Redisson
来实现。小编也是看了官网慢慢的摸索清楚,特写此记录一下。从官网到整合Springboot到源码解读,以单节点为例。
二、为什么使用Redisson
1. 我们打开官网
redis中文官网
2. 我们可以看到官方让我们去使用其他
3. 打开官方推荐
4. 找到文档
Redisson地址
5. Redisson结构
三、Springboot整合Redisson
1. 导入依赖
2. 以官网为例查看如何配置
3. 编写配置类
importorg.redisson.Redisson;importorg.redisson.api.RedissonClient;importorg.redisson.config.Config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;/***@authorwangzhenjun*@date2022/2/99:57*/@ConfigurationpublicclassMyRedissonConfig{/***所有对redisson的使用都是通过RedissonClient来操作的*@return*/@Bean(destroyMethod="shutdown")publicRedissonClientredisson(){//1.创建配置Configconfig=newConfig();//一定要加redis://config.useSingleServer().setAddress("redis://192.168.17.130:6379");//2.根据config创建出redissonClient实例RedissonClientredissonClient=Redisson.create(config);returnredissonClient;}}
4. 官网测试加锁例子
5. 根据官网简单Controller接口编写
@ResponseBody@GetMapping("/hello")publicStringhello(){//1.获取一把锁,只要锁名字一样,就是同一把锁RLocklock=redisson.getLock("my-lock");//2.加锁lock.lock();//阻塞试等待默认加的都是30s//带参数情况//lock.lock(10,TimeUnit.SECONDS);//10s自动解锁,自动解锁时间一定要大于业务的执行时间。try{System.out.println("加锁成功"+Thread.currentThread().getId());Thread.sleep(30000);}catch(InterruptedExceptione){e.printStackTrace();}finally{//3.解锁System.out.println("解锁成功:"+Thread.currentThread().getId());lock.unlock();}return"hello";}
6. 测试
四、lock.lock()源码分析
1. 打开RedissonLock实现类
2. 找到实现方法
@Overridepublicvoidlock(){try{//我们发现不穿过期时间源码默认过期时间为-1lock(-1,null,false);}catch(InterruptedExceptione){thrownewIllegalStateException();}}
3. 按住Ctrl进去lock方法
privatevoidlock(longleaseTime,TimeUnitunit,booleaninterruptibly)throwsInterruptedException{//获取线程的id,占有锁的时候field的值为UUID:线程号idlongthreadId=Thread.currentThread().getId();//尝试获得锁Longttl=tryAcquire(leaseTime,unit,threadId);//lockacquired获得锁,返回if(ttl==null){return;}//这里说明获取锁失败,就通过线程id订阅这个锁RFuture
4. 进去尝试获取锁方法
privateLongtryAcquire(longleaseTime,TimeUnitunit,longthreadId){//直接进入异步方法returnget(tryAcquireAsync(leaseTime,unit,threadId));}private
5. 查看tryLockInnerAsync()方法
6. 进入4留下的定时任务scheduleExpirationRenewal()方法
一步步往下找源码:scheduleExpirationRenewal --->renewExpiration
根据下面源码,定时任务刷新时间为:internalLockLeaseTime / 3,是看门狗的1/3,即为10s刷新一次
privatevoidrenewExpiration(){ExpirationEntryee=EXPIRATION_RENEWAL_MAP.get(getEntryName());if(ee==null){return;}Timeouttask=commandExecutor.getConnectionManager().newTimeout(newTimerTask(){@Overridepublicvoidrun(Timeouttimeout)throwsException{ExpirationEntryent=EXPIRATION_RENEWAL_MAP.get(getEntryName());if(ent==null){return;}LongthreadId=ent.getFirstThreadId();if(threadId==null){return;}RFuture
五、lock.lock(10, TimeUnit.SECONDS)源码分析
1. 打开实现类
@Overridepublicvoidlock(longleaseTime,TimeUnitunit){try{//这里的过期时间为我们输入的10lock(leaseTime,unit,false);}catch(InterruptedExceptione){thrownewIllegalStateException();}}
2. 方法lock()
实现展示,同三.3源码
3. 直接来到尝试获得锁tryAcquireAsync()
方法
private
4. 打开tryLockInnerAsync()
方法
我们不难发现和没有传过期时间的方法一样,只不过leaseTime的值变了。
六、lock.unlock()源码分析
1. 打开方法实现
@Overridepublicvoidunlock(){try{//点击进入释放锁方法get(unlockAsync(Thread.currentThread().getId()));}catch(RedisExceptione){if(e.getCause()instanceofIllegalMonitorStateException){throw(IllegalMonitorStateException)e.getCause();}else{throwe;}}//Future
2. 打开unlockAsync()
方法
@OverridepublicRFuture
3. 打开unlockInnerAsync()
方法
protectedRFuture
感谢你能够认真阅读完这篇文章,希望小编分享的“Springboot基于Redisson如何实现Redis分布式可重入锁源码解析”这篇文章对大家有帮助,同时也希望大家多多支持恰卡编程网,关注恰卡编程网行业资讯频道,更多相关知识等着你来学习!
推荐阅读
-
vue动态添加删除输入框(springboot vue怎么让数据库显示出来)
springbootvue怎么让数据库显示出来?一般情况下是前端调阅后端接口,来获取到数据库的数据,后端哪里会把数据库的数据整理...
-
php如何让Swoole/Pool进程池实现Redis持久连接
php如何让Swoole/Pool进程池实现Redis持久连接本篇...
-
php操作redis大全记录
php连接redis测试˂?php$redis=newRedis();$redis-˃conne...
-
PHP经典高级工程师面试题
1.PHP如何实现不用自带的cookie函数为客户端下发cookie。对于分布式系统,如何来保存session值...
-
PHP操作Redis数据库
-
php利用redis防止商品超发来限制抢购,简单又实用
-
php如何实现秒杀功能?php+redis模拟简单抢购场景,快来看看吧
-
PHP高级工程师面试题
-
Laravel结合Redis发送邮箱验证码
-
使用redis缓存实现多服务器PHP sessions共享