1.为何要构建分布式锁redis
由于多实例的分布式运行状况下,某些代码块会存在竞争关系,例如定时关单,假如部署的tomcat集群为3台A,B,C,有一个定时任务,去清除过时订单,则Tomcat 会出现同时执行某个任务的状况tomcat
2.redis分布式锁原理多线程
使用setnx getset指令分布式
// @Scheduled(cron="0 */1 * * * ?")//每1分钟(每一个1分钟的整数倍) public void closeOrderTaskV3() throws InterruptedException { //防死锁分布式锁 long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","50000"));//锁50秒有效期 //项目因为历史数据关单订单比较多,须要处理,初次用50s时间,后续改为5s便可.同时50s也为了讲课debug的时候时间长而设置。 //你们能够根据实际状况,若是历史订单都处理完毕,或者在外部进行洗数据ok,这里的lock的时间应该设置小一些,例如1s 2s 3s 4s 5s就足够啦。 //这个时间如何用呢,看下面。和时间戳结合起来用。 Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis()+lockTimeout)); if(setnxResult != null && setnxResult.intValue() == 1){ //若是返回值是1,表明设置成功,获取锁 closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK); }else{ //若是setnxResult==null 或 setnxResult.intValue() ==0 即 != 1的时候 //未获取到锁,继续判断,判断时间戳,看是否能够重置获取到锁 String lockValueStr = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK); //若是lockValue不是空,而且当前时间大于锁的有效期,说明以前的lock的时间已超时,执行getset命令. 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值,获取旧的值。 //运用多线程的CAS原理,只有在旧值没有被修改的状况下,才能拿到锁 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); } }