走了很多弯路,查了很多资料。一开始看很多博客都是用luna脚本来写的。后面发现,那种方式无法使用。并不兼容。
回归本源,整理一下,如何去做这个分布式锁;
redis提供了一个很好的工具。setnx key value; 简单理解一下就是:如果不存在(if not exist),设置这个key-value键值对。所以我们可以以这种思路去加锁:
循环{
if(set k-v) 退出循环;
else {休眠;}
}
代码实现如下:
@Autowired
public RedisUtil(RedisTemplate redisTemplate,StringRedisTemplate stringRedisTemplate){
this.redisTemplate = redisTemplate;
this.operations = redisTemplate.opsForValue();
}
public String setLock(String key) {
String uuid = UUID.randomUUID().toString();//用于释放锁
boolean status = false;
try{
while(true) {
status = operations.setIfAbsent("setnxkey", uuid);
if (status) {//获取到了锁
redisTemplate.expire(key, expire, TimeUnit.SECONDS);//设置超时时间
break;
} else {//获取锁失败的时候,判断一下是否没有超时时间,如果没有,那么可能这个是其他客户端获取的时候失败。加一个超时时间
long expiretemp = redisTemplate.getExpire(key);
if(expiretemp == -1) redisTemplate.expire(key, expire, TimeUnit.SECONDS);//设置超时时间
Thread.sleep(expire);
}
}}catch (Exception e){
return "-1";
}
// operations.seti
return uuid;
}
释放锁:
public boolean releaseLock(String key,String uuid) {
/**
* 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除
* 先判断一下当前持有锁的是否是当前的进程,如若不是,则放弃锁
*/
String value = operations.get(key).toString();
if(!value.equals(uuid)) return true;
redisTemplate.delete(key);
return false;
}