zoukankan      html  css  js  c++  java
  • spring cloud 用redis做分布式锁(解决分布式多节点情况下,定时任务多次执行)

     我们知道现在微服务很流行,为此,许多中小型企业都将自己以前的框架加以改造,其中以SpringCloud为最多,但是SpringCloud如果要加定时任务的话,在单台服务器上很好支持,

    但是涉及到集群服务(多台服务的话)就要用到分布式锁了,最简单的方案是用Redis,好了废话不多说,直接上代码.

    1、分布式锁

    /**
     * 分布式锁
     * 
     *
     */
    @Component
    public class DistributedLockHandler {
    
       private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class);
    
       /**
        * 最大持有锁的时间(毫秒)
        */
       private final static long LOCK_EXPIRE = 30 * 1000L;
    
       /**
        * 尝试获取锁的时间间隔(毫秒)
        */
       private final static long LOCK_TRY_INTERVAL = 30L;
    
       /**
        * 获取锁最大等待时间( 毫秒 )
        */
       private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;
    
       @Resource(name = "customRedisTemplate")
       private RedisTemplate<String, String> template;
    
       /**
        * 尝试获取 分布式锁
        * 
        * @param lockKey
        *            锁名
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLock(String lockKey) {
          return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_TRY_INTERVAL);
       }
    
       /**
        * 尝试获取 分布式锁(不自动释放锁)
        * 
        * @param lockKey
        *            锁名
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLockNotAutoRelease(String lockKey) {
          return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, -1);
       }
    
       /**
        * 尝试获取 分布式锁
        * 
        * @param lockKey
        *            锁名
        * @param timeout
        *            获取锁最大等待时间
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLock(String lockKey, long timeout) {
          return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
       }
    
       /**
        * 尝试获取 分布式锁(不自动释放锁)
        * 
        * @param lockKey
        *            锁名
        * @param timeout
        *            获取锁最大等待时间
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLockNotAutoRelease(String lockKey, long timeout) {
          return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, -1);
       }
    
       /**
        * 尝试获取 分布式锁
        * 
        * @param lockKey
        *            锁名
        * @param timeout
        *            获取锁最大等待时间
        * @param tryInterval
        *            获取锁尝试 时间间隔
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLock(String lockKey, long timeout, long tryInterval) {
          return getLock(lockKey, timeout, tryInterval, LOCK_EXPIRE);
       }
    
       /**
        * 尝试获取 分布式锁(不释放锁)
        * 
        * @param lockKey
        *            锁名
        * @param timeout
        *            获取锁最大等待时间
        * @param tryInterval
        *            获取锁尝试 时间间隔
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLockNotAutoRelease(String lockKey, long timeout, long tryInterval) {
          return getLock(lockKey, timeout, tryInterval, -1);
       }
    
       /**
        * 尝试获取 分布式锁
        * 
        * @param lockKey
        *            锁名
        * @param timeout
        *            获取锁最大等待时间
        * @param tryInterval
        *            获取锁尝试 时间间隔
        * @param lockExpireTime
        *            锁最大持有时间
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean tryLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
          return getLock(lockKey, timeout, tryInterval, lockExpireTime);
       }
    
       /**
        * 获取分布式锁
        * 
        * @param lockKey
        *            锁名
        * @param timeout
        *            获取锁最大等待时间
        * @param tryInterval
        *            获取锁尝试 时间间隔
        * @param lockExpireTime
        *            锁最大持有时间
        * @return true 得到了锁 ,false 获取锁失败
        */
       public boolean getLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
          try {
             if (StringUtils.isEmpty(lockKey)) {
                return false;
             }
             long startTime = System.currentTimeMillis();
             do {
                ValueOperations<String, String> ops = template.opsForValue();
                if (ops.setIfAbsent(lockKey, "lockValue")) {
                   if (lockExpireTime > 0) {
                      template.expire(lockKey, lockExpireTime, TimeUnit.MILLISECONDS);
                   }
                   return true;
                }
                Thread.sleep(tryInterval);
             } while (System.currentTimeMillis() - startTime < timeout);
          } catch (InterruptedException e) {
             logger.error(e.getMessage());
             return false;
          }
          return false;
       }
    
       /**
        * 释放锁
        * 
        * @param lockKey
        */
       public void unLock(String lockKey) {
          if (!StringUtils.isEmpty(lockKey)) {
             template.delete(lockKey);
          }
       }
    
    }

    2、 在定时任务中使用

    @Component
    public class AutoComfirmReceied {
       private static final Logger logger = LoggerFactory.getLogger(AutoComfirmReceied.class);
    
       @Resource
       OrderService orderService;
       
       @Resource
       OrderItemMapper orderItemMapper;
       
       @Autowired
       DistributedLockHandler distributedLockHandler;
       
       @Scheduled(cron = "${cron.autoComfirmReceied}")
       public void run() {
          String lockKey = RedisKeyResolver.getLockkey( "AutoComfirmReceied:run" );;
          
          if( distributedLockHandler.tryLockNotAutoRelease( lockKey ) ) {
             try {
                runTask();
             } catch (Exception e) {
                e.printStackTrace();
             }finally {
                distributedLockHandler.unLock( lockKey );
             }
          }else {
             if( logger.isDebugEnabled() ) {
                logger.debug("没有获取锁超时..............");
             }
          }
          
       }
    
       
        private void runTask() {
          logger.info("3分钟执行一次定时任务" + System.currentTimeMillis());
          List<String> orderItemReturnStatus = new ArrayList<>();
          orderItemReturnStatus.add(OrderItemReturnStatus.WTH.name());
          orderItemReturnStatus.add(OrderItemReturnStatus.YJJ.name());
          orderItemReturnStatus.add(OrderItemReturnStatus.YQX.name());
    
          OrderItemExample orderItemExample = new OrderItemExample();
          OrderItemExample.Criteria oderc = orderItemExample.createCriteria();
          oderc.andIsDelEqualTo(false)
                .andOrderStatusEqualTo(OrderItemStatus.SENDED.name())
                .andReturnStatusIn(orderItemReturnStatus)
                .andShippingStatusEqualTo(OrderItemShippingStatus.YFH.name());
    
    
          List<OrderItem> orderItemList = orderItemMapper.selectByExample(orderItemExample);
          Set<String> set = new HashSet<>();
          for (OrderItem orderItem : orderItemList) {
             Long sendTime10 = AutoConfirmReceivedDateUtil.getAdd10Day(orderItem.getSendDate(), 10);
             Long currentTime = new Date().getTime();
             if(currentTime > sendTime10){ //当前时间大于,发货后10天的时间,则确认收货
                set.add(orderItem.getLogisticsId() + "," + orderItem.getUserId());
             }
          }
    
          if(!set.isEmpty()){
             for (String orderItem : set) {
                String[] item = orderItem.split(",");
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append("超过10天自动确认收货,logisticsId:" + item[0] + ",userId:" + item[1]);
                orderService.confirmReceive(Long.valueOf(item[0]), Long.valueOf(item[1]));
                stringBuffer.append(",成功!");
                logger.info(stringBuffer.toString());
    
             }
          }
       }
    }
  • 相关阅读:
    代码演示C#各版本新功能
    有关taro的路由的问题
    优秀的基于VUE移动端UI框架合集
    前端开发应该关注的前沿技术
    let与const的区别
    vue2.0 watch里面的 deep和immediate作用
    Flink MiniCluster 启动流程
    Windows把执行命令值赋值给变量
    Ubuntu时间比正常时间多8小时,设置重启以后时间又多8小时解决办法
    Windows下使用命令实现类似awk命令
  • 原文地址:https://www.cnblogs.com/longyao/p/11719931.html
Copyright © 2011-2022 走看看