重庆小潘seo博客

当前位置:首页 > 重庆网络营销 > 小潘杂谈 >

小潘杂谈

redis会发生死锁问题吗

时间:2020-09-22 14:20:11 作者:重庆seo小潘 来源:
就分布式锁而言,一个常用的问题就是如果一个服务setnx成功了,但是在解锁的时候如果发生了宕机或者一些特殊因素,导致无法解锁,那么其他服务将陷入死锁的状态。所以,我们在用 setnx 的同时想着去用 expire 指令对锁进行一个过期操作, 从指令可以看出 setn

redis会发生死锁问题吗

就分布式锁而言,一个常用的问题就是如果一个服务setnx成功了,但是在解锁的时候如果发生了宕机或者一些特殊因素,导致无法解锁,那么其他服务将陷入死锁的状态。所以,我们在用 setnx 的同时想着去用 expire 指令对锁进行一个过期操作, 从指令可以看出 setnx 和expire指令是分开的,如果在这中间的空隙过程中如果有特殊因素导致指令无法继续,也会导致死锁的产生。

解决方法:import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils; @Componentpublic class RedisLock {Logger logger = LoggerFactory.getLogger(this.getClass());@Autowiredprivate StringRedisTemplate redisTemplate;/*** 加锁* @param key* @param value 当前时间 + 超时时间* @return*/public boolean lock(String key, String value) {if (redisTemplate.opsForValue().setIfAbsent(key, value)) {// 这个其实就是setnx命令,只不过在java这边稍有变化,返回的是boolean// 设置个过期时间,当然如果在这中间的空隙过程中如果有特殊因素导致指令无法继续,也会导致死锁的产生,如果死锁出现,则后续代码会处理redisTemplate.expire(key, lockTime, TimeUnit.SECONDS);return true;}// 避免死锁,且只让一个线程拿到锁String currentValue = redisTemplate.opsForValue().get(key);// 如果锁过期了if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {//获取上一个锁的时间String oldValues = redisTemplate.opsForValue().getAndSet(key, value);/*只会让一个线程拿到锁如果旧的value和currentValue相等,只会有一个线程达成条件,因为第二个线程拿到的oldValue已经和currentValue不一样了*/if (!StringUtils.isEmpty(oldValues) && oldValues.equals(currentValue)) {return true;}}return false;}/*** 解锁* @param key* @param value*/public void unlock(String key, String value) {try {String currentValue = redisTemplate.opsForValue().get(key);if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {redisTemplate.opsForValue().getOperations().delete(key);}} catch (Exception e) {logger.error("redis分布式锁解锁异常,{}", e);}}}调用: //加锁long time = System.currentTimeMillis() + 1000 * lockTime //超时时间:10秒,最好设为常量boolean isLock = redisLock.lock(...keyName, String.valueOf(time));if(!isLock){throw new RuntimeException("系统正忙");}// doSomething...//解锁redisLock.unlock(...keyName, String.valueOf(time));更多Redis相关知识,请访问Redis使用教程栏目!以上就是redis会发生死锁问题吗的详细内容,更多请关注小潘博客其它相关文章!