package com.fdkankan.redis.util; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.Objects; import java.util.concurrent.TimeUnit; @Component @Slf4j public class RedisLockUtil { @Autowired private RedisTemplate redisTemplate; private static final String UNLOCK_LUA = "if redis.call('get',KEYS[1]) == ARGV[1] then\n" + " return redis.call('del',KEYS[1])\n" + "else\n" + " return 0\n" + "end"; /** * 加锁,自旋重试三次 * * @param lockKey 锁key * @param expireTime 锁过期时间 单位 毫秒 * @return */ public boolean lock(String lockKey, int expireTime) { boolean locked = false; int tryCount = 3; String threadId = String.valueOf(Thread.currentThread().getId()); while (!locked && tryCount > 0) { locked = redisTemplate.opsForValue().setIfAbsent(lockKey, threadId, expireTime, TimeUnit.SECONDS); tryCount--; try { Thread.sleep(300); } catch (InterruptedException e) { log.error("线程被中断[线程id:" + threadId + "]", e); } } return locked; } /** * 非原子解锁,可能解别人锁,不安全 * * @return */ public boolean unlock(String lockKey) { String threadId = String.valueOf(Thread.currentThread().getId()); if (StrUtil.isEmpty(lockKey) || Objects.isNull(threadId)) return false; boolean releaseLock = false; Long val = (Long) redisTemplate.opsForValue().get(lockKey); if (threadId.equals(val)) { releaseLock = redisTemplate.delete(lockKey); } return releaseLock; } /** * 使用lua脚本解锁,不会解除别人锁 * * @param * @return */ public boolean unlockLua(String lockKey) { String threadId = String.valueOf(Thread.currentThread().getId()); if (StrUtil.isEmpty(lockKey) || Objects.isNull(threadId)) return false; DefaultRedisScript redisScript = new DefaultRedisScript(); // redisScript.setLocation(new ClassPathResource("unlock.lua")); redisScript.setScriptText(UNLOCK_LUA); redisScript.setResultType(Long.class); Object result = redisTemplate.execute(redisScript, Arrays.asList(lockKey), threadId); return result.equals(Long.valueOf(1)); } }