redis会发生死锁问题吗

互联网 19-6-28

就分布式锁而言,一个常用的问题就是如果一个服务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;   @Component public class RedisLock {       Logger logger = LoggerFactory.getLogger(this.getClass());       @Autowired     private 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会发生死锁问题吗的详细内容,更多内容请关注技术你好其它相关文章!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:redis一般存储什么类型数据

相关资讯