当前位置: 移动技术网 > IT编程>开发语言>Java > springboot设置redis全局锁

springboot设置redis全局锁

2020年07月17日  | 移动技术网IT编程  | 我要评论
代码环境: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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网