springboot设置redis全局锁
程序员文章站
2022-12-20 13:31:55
代码环境:spring boot项目如何用redis设置一个全局锁,如何保证在服务器不可用时,锁可以安全释放?废话不多说,上代码,如遇到任何问题,可随时留言import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.dao.DataAccessException;import org.springframework.data.redis.connection.RedisConnection;....
代码环境:spring boot项目
如何用redis设置一个全局锁,如何保证在服务器不可用时,锁可以安全释放?废话不多说,上代码,如遇到任何问题,可随时留言
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.lang.Nullable;
/**
* Created by jiangtenglong no 2020/6/3 .
*/
public class RedisLock {
Logger logger = LoggerFactory.getLogger(RedisLock.class);
//默认锁的等待时间
private int waitTime = 10 * 1000;
//每次循环所等待的时间
private static final int sleepTime = 100;
/**
* 锁超时时间,防止线程在入锁以后,无限的执行等待,设置为30秒
*/
private int expireTimes = 30 * 1000;
private boolean locked;
private String lockKey;
//锁定的时间
private long expiresLock;
RedisTemplate redisTemplate;
public RedisLock(RedisTemplate redisTemplate,RedisLockEnum redisLockEnum,final String key){
this.redisTemplate = redisTemplate;
this.lockKey = String.format(redisLockEnum.getKeyHead(),key);
}
public RedisLock(RedisTemplate redisTemplate,RedisLockEnum redisLockEnum,final String key,int waitTime){
this.redisTemplate = redisTemplate;
this.lockKey = String.format(redisLockEnum.getKeyHead(),key);
this.waitTime = waitTime;
}
public RedisLock(RedisTemplate redisTemplate,RedisLockEnum redisLockEnum,final String key,int waitTime,int expireTimes){
this.redisTemplate = redisTemplate;
this.lockKey = String.format(redisLockEnum.getKeyHead(),key);
this.waitTime = waitTime;
this.expireTimes = expireTimes;
}
public synchronized boolean lock() throws InterruptedException {
int times = waitTime;
while (times>0){
long expires = System.currentTimeMillis() + expireTimes + 1;
String expiresStr = String.valueOf(expires); //锁到期时间
if (this.setNX(lockKey, expiresStr)) {//尝试抢锁
logger.info("获取锁成功");
locked = true;
expiresLock = expires;
return true;
}
logger.info("获取锁失败,等待获取锁");
//没抢到锁,尝试获取锁对应的时间,看是不是获取锁的那个线程完蛋了
String currentValueStr = this.get(lockKey); //redis里的时间
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {//锁的时间已经超时了
String oldValueStr = this.getSet(lockKey, expiresStr);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
logger.info("上一个线程超时,本次获取锁成功");
expiresLock = expires;
locked = true;
return true;
}
}
times -= sleepTime;
Thread.sleep(sleepTime);
}
return false;
}
//进行setNx获取锁
private boolean setNX(final String key,final String value){
Object object = null;
try {
object = redisTemplate.execute(new RedisCallback<Object>() {
@Nullable
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
StringRedisSerializer serializer = new StringRedisSerializer();
boolean successLock = redisConnection.setNX(serializer.serialize(key), serializer.serialize(value));
redisConnection.close();
return successLock;
}
});
}catch (Exception e){
logger.error("redis 锁异常 key:"+key,e);
}
return object != null ? (Boolean) object : false;
}
private String get(final String key) {
Object obj = null;
try {
obj = redisTemplate.execute(new RedisCallback<Object>() {
@Nullable
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
StringRedisSerializer serializer = new StringRedisSerializer();
byte[] data = redisConnection.get(serializer.serialize(key));
redisConnection.close();
if (data == null) {
return null;
}
return serializer.deserialize(data);
}
});
} catch (Exception e) {
logger.error("redis 异常 key:"+key,e);
}
return obj != null ? obj.toString() : null;
}
private String getSet(final String key, final String value) {
Object object = null;
try {
object = redisTemplate.execute(new RedisCallback<Object>() {
@Nullable
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
StringRedisSerializer serializer = new StringRedisSerializer();
byte[] ret = connection.getSet(serializer.serialize(key), serializer.serialize(value));
connection.close();
return serializer.deserialize(ret);
}
});
} catch (Exception e) {
logger.error("redis 异常 key:"+key,e);
}
return object != null ? (String) object : null;
}
private void delete(final String key){
try {
redisTemplate.execute(new RedisCallback<Object>() {
@Nullable
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
StringRedisSerializer serializer = new StringRedisSerializer();
Long ret = connection.del(serializer.serialize(key));
connection.close();
return ret;
}
});
} catch (Exception e) {
logger.error("redis 异常 key:"+key,e);
}
}
public synchronized void unlock() {
logger.info("尝试删除锁状态");
String currentValueStr = this.get(lockKey); //redis里的时间
if (locked) {
logger.info("准备判定是否还为自己的锁"+currentValueStr+"——"+expiresLock);
if (currentValueStr != null && Long.parseLong(currentValueStr) == expiresLock) {//锁的时间是我自己设置的那个时间,才可以解锁,否则可能是已经超时被别的线程拿到了锁,此时,我不能删除
// redisTemplate.delete(lockKey);
this.delete(lockKey);
currentValueStr = this.get(lockKey); //redis里的时间
logger.info("查看是否删除成功:"+currentValueStr);
locked = false;
}
}
}
}
/**
* redis锁的枚举维护类
* Created by jiangtenglong no 2020/6/3 .
*/
public enum RedisLockEnum {
LOCK_KEY("LOCK_KEY_%s","锁枚举头");
RedisLockEnum(String keyHead,String describe){
this.keyHead=keyHead;
this.describe=describe;
};
private String keyHead;
private String describe;
public String getKeyHead() {
return keyHead;
}
public void setKeyHead(String keyHead) {
this.keyHead = keyHead;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
}
使用方法
RedisLock lock = new RedisLock(redisTemplate, RedisLockEnum.LOCK_KEY,"锁的key"); try{ if(lock.lock()){ System.out.println("获取锁成功"); } }catch (Exception e){ //异常处理 }finally { //锁释放 lock.unlock(); }
本文地址:https://blog.csdn.net/debushiwo/article/details/107347076