利用redis实现 分布式锁
利用redis实现 分布式锁
1.给需要添加锁的地方添加锁
@GetMapping("/get")
public String test(HttpServletRequest request) throws InterruptedException {
System.out.println("begin to do");
String requestId = request.getSession().getId();
String lockName = "Lock_Common_Dict_test";
System.out.println("requestId " + requestId);
boolean flag = this.authorityStore.tryGetDistributedLock(new Memo.Builder(lockName).value(requestId).expireTime(-1).build());
try{
if(flag) {
Integer testKeyNum = (Integer) this.authorityStore.get("testKey");
System.out.println("testKey " + testKeyNum);
Thread.sleep(10000);
if (testKeyNum < 1) {
System.out.println("testKeyNum < 0> will return");
return "testKeyNum < 0 will return;";
}
int i = 2/0;
--testKeyNum;
System.out.println("complete testkey ++");
this.authorityStore.save(new Memo.Builder("testKey").value(testKeyNum).expireTime(10000).build());
return "success;";
} else{
return "can not call now";
}
}
catch (Exception ex){
logger.error("running error");
ex.printStackTrace();
}finally {
this.authorityStore.releaseDistributedLock(lockName, requestId);
}
return "can not call now";
}
2.redis添加锁,释放锁
@Override public boolean tryGetDistributedLock(Memo memo) { String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end"; RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class); boolean beginDog = false; int expireTime = memo.expireTime(); if (expireTime == -1) { expireTime = RedisUtil.lockWatchdogTimeout; beginDog = true; } Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(), Collections.singletonList(memo.key()), memo.value(), expireTime + ""); boolean equals = SUCCESS.equals(result); if (equals && beginDog) { lockWatchdog.beginLockWatchdog(memo.key(), memo.value().toString()); } return equals; } public boolean releaseDistributedLock(String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class); Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(), Collections.singletonList(lockKey), requestId); return SUCCESS.equals(result); }
3.添加看门狗, 给未执行完的key延长时间
// watch dog public class LockWatchdog { private Timer TIMER = new Timer(); /** * 开启一个看门狗 * * @param lockKey * @return */ public void beginLockWatchdog(String lockKey, String val) { renewExpiration(lockKey, val); } /** * 延长锁过期时间 * * @param * @return */ private void renewExpiration(String lockKey, String val) { TIMER.schedule(new TimerTask() { @Override public void run() { try { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end"; RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class); Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(), Collections.singletonList(lockKey), val, String.valueOf(lockWatchdogTimeout)); if (Objects.equals(result, 1L)) { renewExpiration(lockKey, val); } } catch (Exception e) { logger.error("redis锁延长失败!", e); } } }, lockWatchdogTimeout * 1000 / 3L); } }
---不要装作很努力

浙公网安备 33010602011771号