RedisTemplate实现分布式锁

@Component
public class RedisDistributedLockUtils {
   private static final String NX = "NX";
   private static final String EX = "EX";

   private static final String LOCK_OK = "OK";

   private static final Long UNLOCK_OK = 1L;

   private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

   private static ThreadLocal LOCK_VALUE = new ThreadLocal() {
      @Override
      protected String initialValue() {
         return UUID.randomUUID().toString();
      }
   };

   private static RedisTemplate redisTemplate;

   @Autowired
   public void setRedisTemplate(RedisTemplate redisTemplate) {
      RedisDistributedLockUtils.redisTemplate = redisTemplate;
   }

   /**
    * @param key
    * @param expireSeconds 过期时间
    * @return
    */
   public static boolean lock(String key, int expireSeconds) {
      return redisTemplate.execute(new RedisCallback() {
         @Override
         public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
            Object nativeConnection = connection.getNativeConnection();
            if (nativeConnection instanceof JedisCluster) {
               JedisCluster jedisCluster = (JedisCluster) nativeConnection;
               String result = jedisCluster.set(key, LOCK_VALUE.get(), NX, EX, expireSeconds);
               return LOCK_OK.equals(result);
            }
            if (nativeConnection instanceof Jedis) {
               Jedis jedis = (Jedis) nativeConnection;
               String result = jedis.set(key, LOCK_VALUE.get(), NX, EX, expireSeconds);
               return LOCK_OK.equals(result);
            }
            return false;
         }
      });
   }

   public static boolean unlock(String key) {
      return redisTemplate.execute(new RedisCallback() {
         @Override
         public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
            Object nativeConnection = connection.getNativeConnection();
            if (nativeConnection instanceof JedisCluster) {
               JedisCluster jedisCluster = (JedisCluster) nativeConnection;
               Object unlock = jedisCluster.eval(UNLOCK_SCRIPT, Collections.singletonList(key), Collections.singletonList(LOCK_VALUE.get()));
               return UNLOCK_OK.equals(unlock);
            }
            if (nativeConnection instanceof Jedis) {
               Jedis jedis = (Jedis) nativeConnection;
               Object unlock = jedis.eval(UNLOCK_SCRIPT, Collections.singletonList(key), Collections.singletonList(LOCK_VALUE.get()));
               return UNLOCK_OK.equals(unlock);
            }
            return false;
         }
      });
   }
}

假如:线程A代码执行时间超过分布式锁时间,这时锁可能已被线程B获取,此时A线程去释放锁可能将B线程获取的锁给释放掉,为防止此异常,加入线程本地UUID值,A线程释放锁时,对比value和A线程UUID不相同,说明是其他线程获取的锁,此时不释放,异常成功规避。

你可能感兴趣的:(RedisTemplate实现分布式锁)