/**
* 使用redis实现分布式锁
* @ReturnType void
* @Date 2018年9月21日 下午6:00:50
* @Param @param key 数据的key
* @Param @param timeout 超时时间(超时未获得锁会报异常)、锁存活最长时间。默认60s, unit: second
*/
public static void lock(String key, Integer timeout){
Assert.notNull(key, "key must not be nul");
if (timeout == null || timeout <= 0) {
timeout = 60;
}
// 初始时间
Instant start = Instant.now();
// 锁的key
String lockKey = LOCK + key;
// 是否获取锁成功
boolean lockStatus = false;
// 循环timeout秒
while (Duration.between(start, Instant.now()).toMillis() <= 1000 * timeout) {
log.info("redis...lock...try get lock->" + lockKey + ", wait->" + (Duration.between(start, Instant.now()).toMillis()) / 1000 + "s, max->" + timeout + "s");
// 锁的过期时间
long expireTime = (System.currentTimeMillis() + (timeout * 1000));
// 尝试上锁
lockStatus = setnx(lockKey, String.valueOf(expireTime), timeout);
// 上锁成功,跳出循环
if (lockStatus) {
break;
}
// 上锁失败,可能是锁被别的地方抢走,或者死锁(生存时间永久,这种需要以下判断时间)
// 先获取,看是否存在这个锁,存在则获取之前的过期时间
long oldExpireTime = Long.parseLong(get(lockKey, "0"));
// 如果锁中的过期时间小于当前系统时间,超时,可以允许别的请求重新获取
if (oldExpireTime < System.currentTimeMillis()) {
// 计算新的过期时间
long newExpireTime = (System.currentTimeMillis() + (timeout * 1000));
// 尝试获取当前锁中的生存时间,并设置新的过期时间进去
String v = getSet(lockKey, String.valueOf(newExpireTime), timeout);
long currentExpireTime = Long.parseLong(StringUtils.isBlank(v)? "0" : v);
// 如果当前锁中的生存时间和之前获取的一致,说明没有被人设置过
if (currentExpireTime == oldExpireTime) {
// 上锁成功
lockStatus = true;
// 跳出循环
break;
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
// 超时
if (!lockStatus) {
throw new RuntimeException("redis lock-> " + lockKey + " fail...timeout : " + timeout);
}
// 上锁成功
log.info("redis...lock...get lock success->" + lockKey);
}
/**
* 如果不存在就设置进去
* @ReturnType boolean
* @Date 2018年9月21日 下午5:51:50
* @Param @param key
* @Param @param value
* @Param @param seconds
* @Param @return
*/
public static boolean setnx(String key, String value, int seconds){ // 请使用StmsRedisTemplate
return execute(key, jedis->{
boolean succ = jedis.setnx(key, value)==1;
if(succ){
jedis.expire(key, seconds);
}
return succ;
});
}
/**
* 从redis获取数据
* @ReturnType String
* @Date 2018年1月23日 上午11:37:00
* @Param @param key
* @Param @param defaultValue 默认值
* @Param @return
*/
public static String get(String key, String defaultValue) {// 请使用StmsRedisTemplate.get
String value = execute(key, jedis->jedis.get(key));
return value == null ? defaultValue : value;
}
public static String getSet(String key, String value, int seconds) { // 请使用StmsRedisTemplate.getSet
return execute(key, jedis->{
String oldValue = jedis.getSet(key, value);
jedis.expire(key, seconds);
return oldValue;
});
}
jedis 实现分布式锁
最新推荐文章于 2025-06-25 16:31:19 发布