使用redis分布式锁来解决集群项目的定时任务冲突问题

Posted 记录点点滴滴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用redis分布式锁来解决集群项目的定时任务冲突问题相关的知识,希望对你有一定的参考价值。

import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;


public class Test {
//  @Scheduled(cron="0 */1 * * * ?")//(每隔1分钟的整数倍)
  public void closeOrderTask(){
      System.out.println("关闭订单定时任务启动");
      long lockTimeout = 5000;//锁存在的时间 这个时间根据具体业务处理时间来设置
      
      Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
      if(setnxResult != null && setnxResult.intValue() == 1){//如果返回值是1,代表设置成功,获取锁。假设程序执行到这里,此时关掉服务器 那么这里有可能出现死锁的问题
          RedisShardedPoolUtil.expire(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,5);//有效期5秒,防止死锁(这里的锁有效期,与上面的lockTimeout值必须统一)
          System.out.println("-----------业务方法开始---------");
          System.out.println("执行业务方法");
          System.out.println("-----------业务方法结束---------");
          RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);//业务方法执行完之后 手动将锁撤销
      }else{
          System.out.println("未获得分布式锁,锁名是:"+Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
      }
      System.out.println("关闭订单定时任务结束");
  }

  @Scheduled(cron="0 */1 * * * ?")//(每隔1分钟的整数倍)
  public void closeOrderTaskV(){
      System.out.println("关闭订单定时任务启动");
      long lockTimeout = 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||lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)){//这种到老锁存在但是已经超时的情况一般是上面遇到的死锁情况
              //设置新锁 并获取老锁的值,getset是一个原子性的方法
              String getSetResult = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
              if(getSetResult == null || (getSetResult != null && StringUtils.equals(lockValueStr,getSetResult))){//老锁消失 或者老锁过期并且老锁未被其他进程操作的情况下 有权利获取锁
                  //真正获取到锁
                  RedisShardedPoolUtil.expire(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,5);//有效期5秒,防止死锁
                  System.out.println("-----------业务方法开始---------");
                  System.out.println("执行业务方法");
                  System.out.println("-----------业务方法结束---------");
                  RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
              }else{
                  System.out.println("没有获取到分布式锁");
              }
          }else{
              System.out.println("没有获取到分布式锁");
          }
      }
      System.out.println("关闭订单定时任务结束");
  }
}

 

以上是关于使用redis分布式锁来解决集群项目的定时任务冲突问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用redis实现分布式锁功能?

基于redis的spring task集群配置

quartz集群分布式(并发)部署解决方案-Spring

spring quartz定时任务集群环境下如何实现只在单个节点运行

集群中定时任务的重复执行

定时任务部署多少台服务器,怎么确保只有一台服务器执行--redis 分布式锁