分布式锁
作者:互联网
1、加锁解决缓存击穿问题
1)本地锁: 使用同步代码块
public Map<String,List<Catalog2Vo>> getCatalogJsonFromDb() { //只要是同一把锁,就能锁住使用这个锁的所有线程 //synchronized (this) SpringBoot项目中所有组件在容器中都是单例的 synchronized (this){ //得到锁之后,需要去缓存中查询一次,如果没有,才继续查询数据库 String result = redisTemplate.opsForValue().get("xxxx"); if(StringUtils.isNotBlank(result )){ return result; } //查询数据库,返回结果 return getResuleFromDb(); } }
2)本地锁在分部式情况下出现的问题
每个本地锁只能锁住当前项目请求过来的10000个请求,多个项目的情况下,依旧会查询多次数据库
2、分布式锁的原理和使用
1)分布式锁出现的问题
死锁:setnx占好了位,业务代码异常或者程序在页面过程中宕机,没有执行删除逻辑,这就造成了死锁问题
解决:设置锁的自动过期,即使没有删除也会自动删除
3、Redisson的使用
整合Redisson作为分布式锁
1)引入依赖
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.0</version> </dependency>
2)配置
/** * @author houChen * @date 2021/10/31 9:37 * @Description: Redisson的配置类 */ @Configuration public class MyRedissonConfig { /** * 所有对Redisson的使用都是通过RedissonClient对象 */ @Bean public RedissonClient redisson(){ //1、创建配置 Config config = new Config(); config.useSingleServer().setAddress("121.40.182.123:6379"); //2、创建RedissonClient return Redisson.create(config); } }
3)测试
mylock.lock() 是阻塞式的,若某个请求没有获取到锁,则一直阻塞在该处。
@ResponseBody @GetMapping("/hello") public String hello(){ //1、获取一把锁,只要锁名一样,就是同一把锁 RLock mylock = redisson.getLock("mylock"); //2、加锁 mylock.lock(); try{ System.out.println("加锁成功,正在执行业务......"+ Thread.currentThread().getId()); Thread.sleep(30000); }catch (Exception e){ }finally { System.out.println("释放锁" + Thread.currentThread().getId()); mylock.unlock(); } return "hello"; }
4)一些问题
当加锁后,程序闪退了,没有执行解锁代码,会不会造成死锁?
不会,因为当锁没有续期时,超过30秒回自动删除
1)锁的自动续期,如果业务超长,运行期间会自动给锁续上30秒。不用担心业务时间长,锁自动过期被删除
2)加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30秒后自动删除
mylock.lock(10, TimeUnit.SECONDS); 10秒后会自动解锁,但是不会续期,所以解锁的时间一定要大于业务执行的时间
1、如果我们传递了锁的超时时间,就发送指令给redis脚本,进行占锁,默认超时就是我们指定的时间
2、如果我们未指定锁的超时时间,就使用30*1000 【LockWatchOutTimeOut看门狗的默认时间】
只要占领成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10秒自动 续期
4、Redisson 读写锁
5、Redisson 闭锁
/** * 闭锁演示 * * 5个班的人都走完了,才能锁大门 */ @GetMapping("/lockDoor") @ResponseBody public String lockDoor() throws InterruptedException { RCountDownLatch door = redisson.getCountDownLatch("door"); door.trySetCount(5); door.await(); //等待闭锁都完成 return "放假了"; } @GetMapping @ResponseBody public String gogogo(@PathVariable("id") Long id){ RCountDownLatch door = redisson.getCountDownLatch("door"); door.countDown(); // 计数减1 return id + "班的人走了"; }
6、Redisson 分布式信号量
/** * 分布式信号量测试 * 车位停车 3车位 当车位为0时,停车操作将会阻塞 * * 可以用来做分布式限流 */ @GetMapping("/park") @ResponseBody public String park() throws InterruptedException { RSemaphore park = redisson.getSemaphore("park"); park.acquire(); //获取一个信号(占一个车位) return "ok"; } @GetMapping("/go") @ResponseBody public String go() throws InterruptedException { RSemaphore park = redisson.getSemaphore("park"); park.release(); //获取一个信号 return "go 车开走啦...."; }
标签:redisson,return,park,Redisson,door,public,分布式 来源: https://www.cnblogs.com/houchen/p/15616649.html