RedisTemplate分布式锁-加锁/解锁的实现
加锁实现
实现逻辑
通过for循环自旋的方式,判断redis中是否存在锁的缓存,存在则放回true,否则判断获取锁的时间是否超时,超时则返回false。
自旋的判断时间是很快的,设置的超时时间如果太长会占用cpu的时间片处理。
加锁的实现方法
/**
* 获取锁的超时时间
*/
private static final long timeout = 300;
/**
* 加锁,无阻塞
* @param key
* @param expireTime
* @return
*/
public Boolean lock(String key, long expireTime) {
String requestId = UUID.randomUUID().toString();
Long start = System.currentTimeMillis();
//自旋,在一定时间内获取锁,超时则返回错误
for (;;){
//Set命令返回OK,则证明获取锁成功
Boolean ret = redisTemplate.opsForValue().setIfAbsent( key, requestId, expireTime,
TimeUnit.SECONDS);
if (ret) {
return true;
}
//否则循环等待,在timeout时间内仍未获取到锁,则获取失败
long end = System.currentTimeMillis() - start;
if (end >= timeout){
return false;
}
}
}
解锁实现
实现逻辑
直接删除锁的缓存即可
解锁的实现方法
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
业务代码的实现
实现逻辑
先判断是否获得锁,是则处理业务代码,并且在最后进行解锁操作,否则循环5次,继续获取锁,能获取到则实现业务方法,不能获取到则返回错误信息
实现方法
/**
* 锁的key前缀
*/
private static final String lockStr = "r_lock_";
/**
* 获取锁最大失败次数
*/
private static final int maxFailCount = 5;
@RequestMapping("/t1")
public void testRedis(){
String key = "test";
// 锁的过期时间,避免死锁,根据业务调整,毫秒
long expireTime = 1000;
//判断是否获得锁
boolean lock = redisService.tryLock(lockStr + key,expireTime);
if(lock){
try {
String result = redisService.get(key);
//处理业务的方法
//TODO
redisService.set(key,result);
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
redisService.del(lockStr + key);
}
}else{
int failCount = 1;
while (failCount <= maxFailCount){
//判断是否获得锁
if (redisService.tryLock(lockStr + key,expireTime)){
//处理业务的方法
//TODO
//解锁
redisService.del(lockStr + key);
}else{
failCount ++;
}
}
throw new RuntimeException("当前创建的数量太多了,请稍后再试。");
}
}
分类:
Redis
标签:
RedisTemplate
, Redis
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通