通过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("当前创建的数量太多了,请稍后再试。");
}
}
原文:https://www.cnblogs.com/f984969594/p/13901398.html