@Scheduled(cron="0 */1 * * * ?") public void closeOrderTaskV3(){ log.info("关闭订单定时任务启动"); //分布式锁超时时间 long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000")); // setnx: 如果redis有这个key则不会执行 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)){// 超时锁已失效 // getSet : 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。 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("关闭订单定时任务结束"); }