如今的项目基本是从单体到多体项目过程。 比如:做定时任务时,第一轮还没有执行完,第二轮又开始要执行了这时候调用lock()传false 则表示不执行。 当然还有很多类似的情况也是可以用到。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
@Lazy(false)
public class RedisLockUtil {
private static Logger logger = LoggerFactory.getLogger(RedisLockUtil.class);
private static RedisTemplate<String, Long> redisTemplate;
private static String prefix = "lock:";
/**
* 默认加锁等待180秒
*/
private static Long waitTime = 180L;
/**
* 默认加锁时长1小时
*/
private static Long lockTime = 3600L;
@Autowired
public void setRedisTemplate(RedisTemplate<String, Long> redisTemplate) {
RedisLockUtil.redisTemplate = redisTemplate;
}
/**
* 分布式阻塞锁,直到锁上或等待超时异常
* @param key
*/
public static void lock(String key){
RedisLockUtil.lock(key, true);
}
/**
* @param key
* @param isWait 如果传false,则不等待直接返回是否锁上
* @return
*/
public static boolean lock(String key, boolean isWait) {
key = getKey(key);
long startTime = System.currentTimeMillis();
try {
while (!RedisLockUtil.setIfAbsent(key)) {
if (!isWait) {
return false;
}
if (System.currentTimeMillis() - startTime >= waitTime * 1000) {
throw new RuntimeException("redis加锁等待超时!");
}
Thread.sleep(100);
}
return true;
} catch (Exception e) {
logger.error("redis锁处理错误!", e);
throw new RuntimeException("redis锁处理错误!", e);
}
}
private static boolean setIfAbsent(String key){
// 上锁
boolean b = redisTemplate.opsForValue().setIfAbsent(key,System.currentTimeMillis());
// 上锁成功设置超时时间并返回
if(b){
redisTemplate.expire(key, lockTime, TimeUnit.SECONDS);
return true;
}
Long v = redisTemplate.opsForValue().get(key);
if(v == null){
return false;
}
// 正在进行中的任务超时了
if(System.currentTimeMillis() - v.longValue() > lockTime * 1000){
Long v2 = redisTemplate.opsForValue().getAndSet(key, System.currentTimeMillis());
if(v2!=null && v2.longValue() == v.longValue()){
redisTemplate.delete(key);
return setIfAbsent(key);
}
}
return false;
}
public static void unLock(String key){
redisTemplate.delete(getKey(key));
}
private static String getKey(String key){
return prefix + key;
}
}