java retlock_springboot设置redis全局锁

代码环境: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() {

@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() {

@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() {

@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() {

@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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值