>  기사  >  데이터 베이스  >  Redis가 교착 상태 문제를 일으킬까요?

Redis가 교착 상태 문제를 일으킬까요?

尚
원래의
2019-06-28 17:10:355471검색

Redis가 교착 상태 문제를 일으킬까요?

분산 잠금과 관련하여 일반적인 문제는 setnx 서비스가 성공했지만 잠금 해제 중에 가동 중지 시간이나 일부 특별한 요인이 있어 잠금을 해제할 수 없는 경우 다른 서비스가 실패한다는 것입니다. 교착 상태. 따라서 setnx를 사용하는 동안에 lock에 대한 만료 작업을 수행하기 위해 만료 명령을 사용하려고 생각하고 있습니다. 명령을 계속할 수 없으며 교착 상태가 발생합니다.

해결책:

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가 교착 상태 문제를 일으킬까요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.