import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Service; import java.util.Collections; import java.util.concurrent.TimeUnit; /** * Redis Lock **/ @Service @RequiredArgsConstructor public class RedisDistributedLockImpl implements DistributedLock { private static final Logger log = LoggerFactory.getLogger(RedisDistributedLockImpl.class); 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 final Long UNLOCK_SUCCESS = 1L; private final RedisTemplate redisTemplate; @Override @SuppressWarnings({"BusyWait", "java:S2142"}) public boolean lock(DistributedLockParam param) { final long tryLockEndTime = param.getTryLockTime() + System.currentTimeMillis(); while (true) { //判断是否超过了,尝试获取锁的时间 if (System.currentTimeMillis() > tryLockEndTime) { return false; } // 尝试获取锁 Boolean ok = redisTemplate.opsForValue().setIfAbsent(param.getKey(), param.getValue(), param.getHoldLockTime(), TimeUnit.MILLISECONDS); if (Boolean.TRUE.equals(ok)) { return true; } try { //获得锁失败,休眠50毫秒再去尝试获得锁,避免一直请求redis,导致redis cpu飙升 Thread.sleep(50); } catch (InterruptedException e) { log.info(e.getMessage()); } } } @Override public boolean unlock(DistributedLockParam param) { if (StringUtils.isBlank(param.getKey()) || StringUtils.isBlank(param.getValue())) { return false; } RedisScript redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class); Long result = redisTemplate.execute(redisScript, Collections.singletonList(param.getKey()), param.getValue()); return UNLOCK_SUCCESS.equals(result); } }