Spring Boot Redis 实现分布式锁,真香,你掌握了多少?

Spring Boot Redis 实现分布式锁,真香,你掌握了多少?,第1张

Spring Boot Redis 实现分布式锁,真香,你掌握了多少?

org.springframework.boot

spring-boot-starter-integration

org.springframework.integration

spring-integration-redis

Spring Boot 基础知识就不介绍了。

配置分布式锁

@Bean(destroyMethod = “destroy”)

public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {

return new RedisLockRegistry(redisConnectionFactory, “lock”);

}

使用示例

@GetMapping("/redis/lock")

public String lock(@RequestParam(“key”) String key) {

for (int i = 0; i < 10; i++) {

new Thread(() -> {

redisLockService.lock(key);            try {

Thread.sleep(3000L);

} catch (InterruptedException e) {

e.printStackTrace();            }            System.out.println(DateFormatUtils.format(new Date(), “yyyy-MM-dd HH:mm:ss”));

redisLockService.unlock(key);        }        ).start();    }    return “OK”;

}

RedisLockService 是我封装了的一个 Redis 锁服务,代码有点多,这里就不贴了,完整的代码示例在 Github 上,大家可以 Star 一下:

https://github.com/javastacks/spring-boot-best-practice

测试:

http://localhost:8080/redis/lock?key=yeah

输出:

2020-06-23 11:15:34

2020-06-23 11:15:37

2020-06-23 11:15:40

2020-06-23 11:15:43

2020-06-23 11:15:46

2020-06-23 11:15:49

2020-06-23 11:15:52

2020-06-23 11:15:55

2020-06-23 11:15:58

2020-06-23 11:16:01

可以看到每个线程需要等上一个线程休眠 3 秒后才能获取到锁。

源码分析


集成完了,会使用了,还得研究下 RedisLockRegistry 的源码,不然遇到什么坑还得再踩一遍。

RedisLockRegistry 有两个类构造器:

  • connectionFactory:Redis 连接工厂

  • registryKey:锁前缀

  • expireAfter:失效时间(非必须项,

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

默认60秒)

所以,我们要注册 expireAfter 这个选项,默认 60 秒是否满足业务需要,如果超过默认的 60 少时间,否则将导致锁失效。

还有两个和 RedisLockRegistry 相关且很重要的成员变量:

private final String clientId = UUID.randomUUID().toString();

private final Map locks = new ConcurrentHashMap<>();

  • clientId:

首先用来标识当前 RedisLockRegistry 实例ID,并且在设置、移除锁的时候都会要用到,用来判断是不是当前的锁注册实例。

  • locks:

用来在内存中缓存当前锁注册实例所有锁对象

获取锁对象

如下面获取锁对象源码所示:

每个 key 在内存中(ConcurrentHashMap)都对应一个锁对象,锁对象有生成过就直接返回,没有就生成再返回,有了这个锁对象才能进行上锁和解锁 *** 作。

这个锁对象(RedisLock)其实也是实现了 Java 中的 java.util.concurrent.locks.Lock 锁接口:

锁对象(RedisLock)也有两个很重要的成员变量:

private final ReentrantLock localLock = new ReentrantLock();

private volatile long lockedAt;

  • localLock:

localLock 是一个本地内存可重入锁,每次去 Redis 上锁前,都要用本地 localLock 上锁先,这样能做到尽可能的少往 Redis 上锁,也能从一方面提升锁的性能。

  • lockedAt:

lockedAt 上锁时间,移除过时锁会用到。

阻塞上锁

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5611616.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存