Advertisement

redis 分布式锁

阅读量:
复制代码
 package cn.admin.srv.util;

    
  
    
 import lombok.extern.slf4j.Slf4j;
    
 import org.springframework.beans.factory.annotation.Autowired;
    
 import org.springframework.data.redis.core.RedisCallback;
    
 import org.springframework.data.redis.core.RedisTemplate;
    
 import org.springframework.stereotype.Component;
    
  
    
 import java.util.Objects;
    
  
    
 @Component
    
 @Slf4j
    
 public class CommonRedisHelper {
    
     public static final String LOCK_PREFIX = "redis_lock";
    
     public static final int LOCK_EXPIRE = 10 * 1000; // 锁过期时间ms
    
  
    
     public static final int LOCK_EXPIRE_WAIT = 100; // 获取锁失败后的等待时间ms,等待时间过去后再次尝试获取
    
  
    
     private static final int LOCK_TIMEOUT = 5 * 1000; //锁等待时间,ms
    
  
    
     @Autowired
    
     RedisTemplate redisTemplate;
    
  
    
  
    
     public boolean lock(String key){
    
     log.info("lock invoke, key = {}", key);
    
     return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
    
         //获取锁的超时时间,超过这个时间还没获取到锁,认为失败
    
         int timeoutMs = LOCK_TIMEOUT;
    
         while (timeoutMs >= 0) {
    
             //锁过期时间
    
             long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
    
             Boolean acquire = connection.setNX(key.getBytes(), String.valueOf(expireAt).getBytes());
    
  
    
             //锁获取成功,直接返回
    
             if (acquire) {
    
                 log.info("lock acquire success, key = {}", key);
    
                 return true;
    
             }
    
  
    
             byte[] value = connection.get(key.getBytes());
    
             boolean isExpired = Objects.nonNull(value) && Long.parseLong(new String(value)) < System.currentTimeMillis();
    
             
    
             //如果当前锁过期 尝试通过更新锁时间 来获取锁
    
             if (isExpired) {
    
                 byte[] oldValue = connection.getSet(key.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
    
                 //如果锁的过期时间值 没有被其他线程修改 则获取锁成功
    
                 if (Objects.nonNull(oldValue) && Objects.equals(Long.parseLong(new String(value)), Long.parseLong(new String(oldValue)))) {
    
                     log.info("lock acquire success2 , key {}", key);
    
                     return true;
    
                 }
    
                 }
    
             //没有获取锁  等待时间 再去获取锁
    
             timeoutMs -= LOCK_EXPIRE_WAIT;
    
             try {
    
                 Thread.sleep(LOCK_EXPIRE_WAIT);
    
             } catch (InterruptedException e) {
    
                 log.error("lock error , key {}",key , e);
    
             }
    
         }
    
         //超时未获取到锁 则获取失败
    
         return false;
    
             });
    
     }
    
  
    
     /** * 删除锁
    
      * * @param key
    
      */
    
     public void deleteLock(String key) {
    
     redisTemplate.delete(key);
    
     log.info("删除lock key {}", key);
    
     }
    
 }

全部评论 (0)

还没有任何评论哟~