redis 分布式 锁 总会用到

如今的项目基本是从单体到多体项目过程。
比如:做定时任务时,第一轮还没有执行完,第二轮又开始要执行了这时候调用lock()传false 则表示不执行。
当然还有很多类似的情况也是可以用到。


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
@Lazy(false)
public class RedisLockUtil {
   
   private static Logger logger = LoggerFactory.getLogger(RedisLockUtil.class);
   
   private static RedisTemplate<String, Long> redisTemplate;
   
   private static String prefix = "lock:";
   /**
    * 默认加锁等待180秒
    */
   private static Long waitTime = 180L;
   /**
    * 默认加锁时长1小时
    */
   private static Long lockTime = 3600L;

   @Autowired
   public void setRedisTemplate(RedisTemplate<String, Long> redisTemplate) {
      RedisLockUtil.redisTemplate = redisTemplate;
   }
   
   /**
    * 分布式阻塞锁,直到锁上或等待超时异常
    * @param key
    */
   public static void lock(String key){
      RedisLockUtil.lock(key, true);
   }

   /**
    * @param key
    * @param isWait 如果传false,则不等待直接返回是否锁上
    * @return
    */
   public static boolean lock(String key, boolean isWait) {
      key = getKey(key);
      long startTime = System.currentTimeMillis();
      try {
         while (!RedisLockUtil.setIfAbsent(key)) {
            if (!isWait) {
               return false;
            }
            if (System.currentTimeMillis() - startTime >= waitTime * 1000) {
               throw new RuntimeException("redis加锁等待超时!");
            }
            Thread.sleep(100);
         }
         return true;
      } catch (Exception e) {
         logger.error("redis锁处理错误!", e);
         throw new RuntimeException("redis锁处理错误!", e);
      }
   }
   
   private static boolean setIfAbsent(String key){
      // 上锁
      boolean b = redisTemplate.opsForValue().setIfAbsent(key,System.currentTimeMillis());
      // 上锁成功设置超时时间并返回
      if(b){
         redisTemplate.expire(key, lockTime, TimeUnit.SECONDS);
         return true;
      }

      Long v = redisTemplate.opsForValue().get(key);
      if(v == null){
         return false;
      }
      // 正在进行中的任务超时了
      if(System.currentTimeMillis() - v.longValue() > lockTime * 1000){
         Long v2 = redisTemplate.opsForValue().getAndSet(key, System.currentTimeMillis());
         if(v2!=null && v2.longValue() == v.longValue()){
            redisTemplate.delete(key);
            return setIfAbsent(key);
         }
      }
      return false;
   }
   
   public static void unLock(String key){
      redisTemplate.delete(getKey(key));
   }
   
   private static String getKey(String key){
      return prefix + key;
   }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值