redis发生死锁问题怎么办

这篇文章主要介绍了redis发生死锁问题怎么办,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获。下面让小编带着大家一起了解一下。

创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于成都网站制作、成都网站建设、花山网络推广、成都小程序开发、花山网络营销、花山企业策划、花山品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联公司为所有大学生创业者提供花山建站搭建服务,24小时服务热线:18980820575,官方网址:www.cdcxhl.com

就分布式锁而言,一个常用的问题就是如果一个服务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发生死锁问题怎么办
URL网址:http://azwzsj.com/article/gejhpc.html