利用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); } }
---不要装作很努力