redis發(fā)生死鎖問題怎么辦

這篇文章主要介紹了redis發(fā)生死鎖問題怎么辦,具有一定借鑒價(jià)值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、花山網(wǎng)絡(luò)推廣、成都小程序開發(fā)、花山網(wǎng)絡(luò)營(yíng)銷、花山企業(yè)策劃、花山品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供花山建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:bm7419.com

就分布式鎖而言,一個(gè)常用的問題就是如果一個(gè)服務(wù)setnx成功了,但是在解鎖的時(shí)候如果發(fā)生了宕機(jī)或者一些特殊因素,導(dǎo)致無法解鎖,那么其他服務(wù)將陷入死鎖的狀態(tài)。所以,我們?cè)谟?setnx 的同時(shí)想著去用 expire 指令對(duì)鎖進(jìn)行一個(gè)過期操作, 從指令可以看出 setnx 和expire指令是分開的,如果在這中間的空隙過程中如果有特殊因素導(dǎo)致指令無法繼續(xù),也會(huì)導(dǎo)致死鎖的產(chǎn)生。

解決方法:

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 當(dāng)前時(shí)間 + 超時(shí)時(shí)間
     * @return
     */
    public boolean lock(String key, String value) {
    
        if (redisTemplate.opsForValue().setIfAbsent(key, value)) {     
            // 這個(gè)其實(shí)就是setnx命令,只不過在java這邊稍有變化,返回的是boolean
            // 設(shè)置個(gè)過期時(shí)間,當(dāng)然如果在這中間的空隙過程中如果有特殊因素導(dǎo)致指令無法繼續(xù),也會(huì)導(dǎo)致死鎖的產(chǎn)生,如果死鎖出現(xiàn),則后續(xù)代碼會(huì)處理
            redisTemplate.expire(key, lockTime, TimeUnit.SECONDS);
            return true;
        }
 
        // 避免死鎖,且只讓一個(gè)線程拿到鎖
        String currentValue = redisTemplate.opsForValue().get(key);
        // 如果鎖過期了
        if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            //獲取上一個(gè)鎖的時(shí)間
            String oldValues = redisTemplate.opsForValue().getAndSet(key, value);
 
            /*
               只會(huì)讓一個(gè)線程拿到鎖
               如果舊的value和currentValue相等,只會(huì)有一個(gè)線程達(dá)成條件,因?yàn)榈诙€(gè)線程拿到的oldValue已經(jīng)和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);
        }
    }
}

調(diào)用:

 //加鎖
    long time = System.currentTimeMillis() + 1000 * lockTime //超時(shí)時(shí)間:10秒,最好設(shè)為常量
 
    boolean isLock = redisLock.lock(...keyName, String.valueOf(time));
    if(!isLock){
        throw new RuntimeException("系統(tǒng)正忙");
    }
    
    // doSomething...
    
    
    //解鎖
    redisLock.unlock(...keyName, String.valueOf(time));

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享redis發(fā)生死鎖問題怎么辦內(nèi)容對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián),詳細(xì)的解決方法等著你來學(xué)習(xí)!

當(dāng)前文章:redis發(fā)生死鎖問題怎么辦
文章位置:http://bm7419.com/article32/gejhpc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、App開發(fā)、企業(yè)網(wǎng)站制作、用戶體驗(yàn)、網(wǎng)站建設(shè)、微信公眾號(hào)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化