关于 Redis 分布式锁这一篇应该是讲的最好的了,赶紧收藏起来
前言
在Java并发编程中,我们通常使用到synchronized 、Lock这两个线程锁,Java中的锁,只能保证对同一个JVM中的线程有效。而在分布式集群环境,这个时候我们就需要使用到分布式锁。
实现分布式锁的方案
基于数据库实现分布式锁
基于缓存Redis实现分布式锁
基于Zookeeper的临时序列化节点实现分布式锁
Redis实现分布式锁
场景:在高并发的情况下,可能有大量请求来到数据库查询三级分类数据,而这种数据不会经常改变,可以引入缓存来存储第一次从数据库查询出来的数据,其他线程就可以去缓存中获取数据,来减少数据库的查询压力。
在集群的环境下,就可以使用分布式锁来控制去查询数据库的次数。
阶段一
得到锁以后,我们应该再去缓存中确定一次,如果没有才需要继续查询,从数据库查到数据以后,应该先把数据放入缓存中,再将数据返回。
阶段二
阶段三
阶段四
阶段五
小总结
stringRedisTemplate.opsForValue().setIfAbsent(“lock”, uuid,300,TimeUnit.SECONDS);
stringRedisTemplate.execute(new DefaultRedisScript(script, Long.class) , Arrays.asList(“lock”), uuid);
使用Redis来实现分布式锁需保证加锁【占位+过期时间】和删除锁【判断+删除】操作的原子性。
Redis锁的过期时间小于业务的执行时间该如何自动续期?设置一个比业务耗时更长的过期时间Redisson的看门狗机制
Redisson实现分布式锁
Redisson 简介
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
原理机制
集成Spring Boot 项目
引入依赖 【可引入Spring Boot 封装好的starter】 <!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.0</version> </dependency>
添加配置类@Configuration public class MyRedissonConfig { @Bean(destroyMethod = "shutdown") public RedissonClient redissonClient(){ // 创建配置 记得加redis:// Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.26.104:6379"); // 根据配置创建RedissClient客户端 RedissonClient redissonClient = Redisson.create(config); return redissonClient; } }
可重入锁 Reentrant Lock
获取一把锁 redissonClient.getLock(“my-lock”);
给业务代码加锁 lock.lock();
解锁 lock.unlock();
看门狗机制 锁会自动续期
lock方法有一个重载方法 lock(long leaseTime, TimeUnit unit)
注意:指定了过期时间后,不会进行自动续期,此时如果有多个线程,即便业务还然在执行,过期时间到了之后,锁就会被释放,其他线程就会争抢到锁。
二个方法对比
如果设置了过期时间,就会发生执行脚本给Redis,进行占锁,设置过期时间为我们指定的时间。
未设置过期时间,就会使用看门狗的默认时间LockWatchdogTimeout 30*1000
只有没有指定过期的时间的方法才有自动续期功能
自动续期实现机制 :只要占锁成功,就会自动启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10s【( internalLockLeasTime)/3】都会自动续期。
持有锁的机器宕机问题,因为来不及续期,所以锁自动被释放,当该机再次恢复时,因为其后台守护线程是ScheduleTask,所以恢复后会马上执行一次watchDog续期逻辑,执行过程中,它会感知到自己已经丢失了锁,所以不存在共同持有的问题。
读写锁 ReadWriteLock
保证一定能读到最新数据,修改期间,写锁是一个互斥锁,读锁是一个共享锁。
写+读 写锁没有释放,读锁就得等待
写+写 阻塞方式
读+写 写锁等待读锁释放才能加锁
读+读 相当于无锁,并发读
信号量 Semaphore
使用信号量来做分布式限流
闭锁 CountDownLatch
模拟场景:等待班级放学走了,保安关校门。
Redisson解决上面Redis查询问题
最后,小编还整理了一份面试宝典,有需要领取的只需要添加小编的vx:mxzFAFAFA就可以免费领取!!!
评论