package cn.admin.srv.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Component
@Slf4j
public class CommonRedisHelper {
public static final String LOCK_PREFIX = "redis_lock";
public static final int LOCK_EXPIRE = 10 * 1000; // 锁过期时间ms
public static final int LOCK_EXPIRE_WAIT = 100; // 获取锁失败后的等待时间ms,等待时间过去后再次尝试获取
private static final int LOCK_TIMEOUT = 5 * 1000; //锁等待时间,ms
@Autowired
RedisTemplate redisTemplate;
public boolean lock(String key){
log.info("lock invoke, key = {}", key);
return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
//获取锁的超时时间,超过这个时间还没获取到锁,认为失败
int timeoutMs = LOCK_TIMEOUT;
while (timeoutMs >= 0) {
//锁过期时间
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
Boolean acquire = connection.setNX(key.getBytes(), String.valueOf(expireAt).getBytes());
//锁获取成功,直接返回
if (acquire) {
log.info("lock acquire success, key = {}", key);
return true;
}
byte[] value = connection.get(key.getBytes());
boolean isExpired = Objects.nonNull(value) && Long.parseLong(new String(value)) < System.currentTimeMillis();
//如果当前锁过期 尝试通过更新锁时间 来获取锁
if (isExpired) {
byte[] oldValue = connection.getSet(key.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
//如果锁的过期时间值 没有被其他线程修改 则获取锁成功
if (Objects.nonNull(oldValue) && Objects.equals(Long.parseLong(new String(value)), Long.parseLong(new String(oldValue)))) {
log.info("lock acquire success2 , key {}", key);
return true;
}
}
//没有获取锁 等待时间 再去获取锁
timeoutMs -= LOCK_EXPIRE_WAIT;
try {
Thread.sleep(LOCK_EXPIRE_WAIT);
} catch (InterruptedException e) {
log.error("lock error , key {}",key , e);
}
}
//超时未获取到锁 则获取失败
return false;
});
}
/**
* 删除锁
*
* @param key
*/
public void deleteLock(String key) {
redisTemplate.delete(key);
log.info("删除lock key {}", key);
}
}
版权声明:本文为weixin_58361879原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。