redis简单的分布式锁实现(乞丐版)
由于公司的redis版本较低,setnx无法同时设置有效时间,容易导致死锁,现写一种简易版分布式锁
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* @author jiangwenzhang
*/
@Component
public class RedisLock {
private static final Logger log =
LoggerFactory.getLogger(RedisLock.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 加锁
*
* @param lockKey 加锁的Key
* @param lockValue 时间戳:当前时间+超时时间
* @return
*/
public boolean lock(String lockKey, String lockValue) {
if (stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockValue)) {
// 对应setnx命令,可以成功设置,也就是key不存在,获得锁成功
return true;
}
//设置失败,获得锁失败
// 判断锁超时 - 防止原来的操作异常,没有运行解锁操作 ,防止死锁
String currentLock = stringRedisTemplate.opsForValue().get(lockKey);
if (!StringUtils.isEmpty(currentLock)) {
String[] split = currentLock.split(":");
// 如果锁过期 currentLock不为空且小于当前时间
if (!StringUtils.isEmpty(split[1]) && Long.parseLong(split[1]) < System.currentTimeMillis()) {
//如果lockKey对应的锁已经存在,获取上一次设置的时间戳之后并重置lockKey对应的锁的时间戳
String preLock = stringRedisTemplate.opsForValue().getAndSet(lockKey, lockValue);
//假设多个线程同时进来这里,因为key被占用了,而且锁过期了。
//获取的值currentLock=A(get取的旧的值肯定是一样的),多个线程的lockValue都不相同,key都是K.锁时间已经过期了。
//而这里面的getAndSet只会有一个线程获取到A,其他线程获取的都不是A。
if (!StringUtils.isEmpty(preLock) && preLock.equals(currentLock)) {
stringRedisTemplate.opsForValue().set(lockKey, lockValue);
return true;
}
}
}
return false;
}
/**
* 释放锁
*
* @param lockKey
* @param lockValue
*/
public void release(String lockKey, String lockValue) {
try {
String currentValue = stringRedisTemplate.opsForValue().get(lockKey);
if (!StringUtils.isEmpty(currentValue) && currentValue.equals(lockValue)) {
// 删除锁状态
stringRedisTemplate.opsForValue().getOperations().delete(lockKey);
}
} catch (Exception e) {
log.error("解锁异常:{}", e);
}
}
}
测试代码
import com.pateo.qingcloud.cp.config.RedisLock;
import com.pateo.qingcloud.cp.testvo.TestVo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.UUID;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MscpchargeApplicationTests {
@Autowired
private RedisLock redisLock;
@Test
public void contextLoads() {
StringBuilder sb = new StringBuilder();
long time = System.currentTimeMillis() + 1000000;
sb.append(UUID.randomUUID().toString());
sb.append(":");
sb.append(time);
String lockValue = sb.toString();
System.out.println(redisLock.lock("ssdsad", lockValue));
System.out.println(redisLock.lock("ssdsad", lockValue));
System.out.println(redisLock.lock("ssdsad", lockValue));
System.out.println(redisLock.lock("ssdsad", lockValue));
}
}
唧唧复唧唧,你是丘处机。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具