waynelone revidoval tento gist 5 months ago. Přejít na revizi
1 file changed, 0 insertions, 0 deletions
RedisDistributedLockImpl.jav přejmenováno na RedisDistributedLockImpl.java
Soubor přejmenován beze změn
waynelone revidoval tento gist 5 months ago. Přejít na revizi
1 file changed, 0 insertions, 0 deletions
gistfile1.txt přejmenováno na RedisDistributedLockImpl.jav
Soubor přejmenován beze změn
waynelone revidoval tento gist 5 months ago. Přejít na revizi
3 files changed, 96 insertions
Demo.java(vytvořil soubor)
| @@ -0,0 +1,14 @@ | |||
| 1 | + | DistributedLockParam lockParam = null; | |
| 2 | + | try { | |
| 3 | + | lockParam = new DistributedLockParam("test:lock:key"); | |
| 4 | + | boolean lockOk = distributedLock.lock(lockParam); | |
| 5 | + | if (!lockOk) { | |
| 6 | + | return new Result().error("系统繁忙,请稍候重试"); | |
| 7 | + | } | |
| 8 | + | // 执行业务逻辑 | |
| 9 | + | } finally { | |
| 10 | + | // 最后强制解锁 | |
| 11 | + | if (lockParam != null) { | |
| 12 | + | distributedLock.unlock(lockParam); | |
| 13 | + | } | |
| 14 | + | } | |
DistributedLock.java(vytvořil soubor)
| @@ -0,0 +1,21 @@ | |||
| 1 | + | /** | |
| 2 | + | * 分布式锁 | |
| 3 | + | */ | |
| 4 | + | public interface DistributedLock { | |
| 5 | + | ||
| 6 | + | /** | |
| 7 | + | * 加锁 | |
| 8 | + | * | |
| 9 | + | * @param param 加锁参数 | |
| 10 | + | * @return 加锁是否成功 | |
| 11 | + | */ | |
| 12 | + | boolean lock(DistributedLockParam param); | |
| 13 | + | ||
| 14 | + | /** | |
| 15 | + | * 解锁 | |
| 16 | + | * | |
| 17 | + | * @param param 加锁参数 | |
| 18 | + | * @return 解锁是否成功 | |
| 19 | + | */ | |
| 20 | + | boolean unlock(DistributedLockParam param); | |
| 21 | + | } | |
gistfile1.txt(vytvořil soubor)
| @@ -0,0 +1,61 @@ | |||
| 1 | + | import lombok.RequiredArgsConstructor; | |
| 2 | + | import org.apache.commons.lang3.StringUtils; | |
| 3 | + | import org.slf4j.Logger; | |
| 4 | + | import org.slf4j.LoggerFactory; | |
| 5 | + | import org.springframework.data.redis.core.RedisTemplate; | |
| 6 | + | import org.springframework.data.redis.core.script.DefaultRedisScript; | |
| 7 | + | import org.springframework.data.redis.core.script.RedisScript; | |
| 8 | + | import org.springframework.stereotype.Service; | |
| 9 | + | ||
| 10 | + | import java.util.Collections; | |
| 11 | + | import java.util.concurrent.TimeUnit; | |
| 12 | + | ||
| 13 | + | /** | |
| 14 | + | * Redis Lock | |
| 15 | + | **/ | |
| 16 | + | @Service | |
| 17 | + | @RequiredArgsConstructor | |
| 18 | + | public class RedisDistributedLockImpl implements DistributedLock { | |
| 19 | + | ||
| 20 | + | private static final Logger log = LoggerFactory.getLogger(RedisDistributedLockImpl.class); | |
| 21 | + | ||
| 22 | + | 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"; | |
| 23 | + | private static final Long UNLOCK_SUCCESS = 1L; | |
| 24 | + | ||
| 25 | + | private final RedisTemplate<String, String> redisTemplate; | |
| 26 | + | ||
| 27 | + | @Override | |
| 28 | + | @SuppressWarnings({"BusyWait", "java:S2142"}) | |
| 29 | + | public boolean lock(DistributedLockParam param) { | |
| 30 | + | final long tryLockEndTime = param.getTryLockTime() + System.currentTimeMillis(); | |
| 31 | + | while (true) { | |
| 32 | + | //判断是否超过了,尝试获取锁的时间 | |
| 33 | + | if (System.currentTimeMillis() > tryLockEndTime) { | |
| 34 | + | return false; | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | // 尝试获取锁 | |
| 38 | + | Boolean ok = redisTemplate.opsForValue().setIfAbsent(param.getKey(), param.getValue(), param.getHoldLockTime(), TimeUnit.MILLISECONDS); | |
| 39 | + | if (Boolean.TRUE.equals(ok)) { | |
| 40 | + | return true; | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | try { | |
| 44 | + | //获得锁失败,休眠50毫秒再去尝试获得锁,避免一直请求redis,导致redis cpu飙升 | |
| 45 | + | Thread.sleep(50); | |
| 46 | + | } catch (InterruptedException e) { | |
| 47 | + | log.info(e.getMessage()); | |
| 48 | + | } | |
| 49 | + | } | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | @Override | |
| 53 | + | public boolean unlock(DistributedLockParam param) { | |
| 54 | + | if (StringUtils.isBlank(param.getKey()) || StringUtils.isBlank(param.getValue())) { | |
| 55 | + | return false; | |
| 56 | + | } | |
| 57 | + | RedisScript<Long> redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class); | |
| 58 | + | Long result = redisTemplate.execute(redisScript, Collections.singletonList(param.getKey()), param.getValue()); | |
| 59 | + | return UNLOCK_SUCCESS.equals(result); | |
| 60 | + | } | |
| 61 | + | } | |