定时器+redis分布式锁、定时器+redisson框架分布式锁

定时器+redis分布式锁

 

在xml中添加:

 

1. 不带锁的定时器:

定时器+redis分布式锁、定时器+redisson框架分布式锁_第1张图片

 

 

2. 带redis分布式锁的定时器:

原理:设置锁的lokkey,值为当前毫秒值+超时毫秒值,redis的setnx方法为,如果不存在lokkey,返回1并设置lokkey,返回0,代表已存在锁

定时器+redis分布式锁、定时器+redisson框架分布式锁_第2张图片

 

代码

定时器+redis分布式锁、定时器+redisson框架分布式锁_第3张图片

 

定时器+redis分布式锁、定时器+redisson框架分布式锁_第4张图片

 

定时器+redis分布式锁、定时器+redisson框架分布式锁_第5张图片

 

3.上面的方法虽然好,但是如果在设置锁的有效期之前,tomcat异常关闭,比如:杀死tomcat进程,在redis中已经存在锁,这种情况会出现死锁,所以需要进行改进

 

优化版:设置锁的lokkey,值为当前毫秒值+超时毫秒值,redis的setnx方法为,如果不存在lokkey,返回1并设置lokkey,返回0,代表已存在锁

返回0时,判断当前时间是否为空&&是否 > redis的value值 lockvalueA

{

不为空且大于:使用getset方法,设置值为当前毫秒+超时毫秒,返回旧值 lockvalueB,判断lockvalueB是否为空 || (lockvalueB不为空且lockvalueA==lockvalueB)

    {

         lockvalueB为空:代表走到这一步,别的tomcat已经执行了一遍代码并且释放了锁

         lockvalueB不为空且lockvalueA==lockvalueB:代表开启定时后第一次执行此代码

         lockvalueA != lockvalueB:代表别的tomcat已经在执行此代码,并且锁还未被释放

    }

不为空且小于:结束

为空:结束

}

定时器+redis分布式锁、定时器+redisson框架分布式锁_第6张图片

 

 

代码

@Scheduled(cron="0 */1 * * * ?")
    public void closeOrderTaskV3(){
        log.info("关闭订单定时任务启动");
        long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
        Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
        if(setnxResult != null && setnxResult.intValue() == 1){
            closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        }else{
            //未获取到锁,继续判断,判断时间戳,看是否可以重置并获取到锁
            String lockValueStr = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            if(lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)){
                String getSetResult = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
                //再次用当前时间戳getset。
                //返回给定的key的旧值,->旧值判断,是否可以获取锁
                //当key没有旧值时,即key不存在时,返回nil ->获取锁
                //这里我们set了一个新的value值,获取旧的值。
                if(getSetResult == null || (getSetResult != null && StringUtils.equals(lockValueStr,getSetResult))){
                    //真正获取到锁
                    closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }else{
                    log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }
            }else{
                log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            }
        }
        log.info("关闭订单定时任务结束");
    }

 

定时器+redis分布式锁、定时器+redisson框架分布式锁_第7张图片

 

 

 

定时器+redisson框架分布式锁

 

使用这个方法代码会简单很多

在pom.xml中添加:


      org.redisson
      redisson
      2.9.0
    
    
      com.fasterxml.jackson.dataformat
      jackson-dataformat-avro
      2.9.0
    

 

 

RedissonManager类

@Component
@Slf4j
public class RedissonManager {

    private Config config = new Config();

    private Redisson redisson = null;

    public Redisson getRedisson() {
        return redisson;
    }

    private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
    private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));
    private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
    private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));

    @PostConstruct
    private void init(){
        try {
            config.useSingleServer().setAddress(new StringBuilder().append(redis1Ip).append(":").append(redis1Port).toString());

            redisson = (Redisson) Redisson.create(config);

            log.info("初始化Redisson结束");
        } catch (Exception e) {
            log.error("redisson init error",e);
        }
    }



}

 

定时器+redis分布式锁、定时器+redisson框架分布式锁_第8张图片

 

你可能感兴趣的:(面包)