Implementación de bloqueo reentrante distribuido de Redis

 

Bloqueo reentrante

 

Un hilo puede adquirir el bloqueo varias veces, lo que indica que el bloqueo es reentrante. Implementemos Redisbloqueos reentrantes distribuidos. Podemos usar ThreadLocalvariables de hilo para almacenar el recuento de bloqueos actual.

 

Código central

 

El siguiente código no es perfecto, pero proporciona una idea.

@Component
public class RedisWithReentrantLock {

    @Autowired
    private RedisTemplate redisTemplate;


    private static final String REDIS_VALUE = "r_lock";

    //ThreadLocal存储,同线程持有锁(key)相同,计数+1
    private ThreadLocal<Map<String, Integer>> lockers = new ThreadLocal<>();

    //相当于setnx + 超时时间
    //这里还有个问题,业务中有可能持有锁的那段代码没有执行完,锁就超时了,这里需要设计一个看门狗线程,去监听线程是否持有锁
    private boolean _lock(String key) {
        return redisTemplate.opsForValue().setIfAbsent(key, REDIS_VALUE, 20, TimeUnit.SECONDS);
    }

    //释放锁
    private void _unlock(String key) {
        redisTemplate.delete(key);
    }

    //获取当前线程持有锁的Map, key为redis的key,value为重入的次数
    private Map<String, Integer> currentLockers() {
        Map<String, Integer> refs = lockers.get();
        if (refs != null) {
            return refs;
        }

        lockers.set(new HashMap<>());
        return lockers.get();
    }

    //可重入加锁
    public boolean lock(String key) {
        Map<String, Integer> refs = currentLockers();
        Integer refCnt = refs.get(key);
        if (refCnt != null) {
            //当前线程下,每获取一次,加一次计数
            refs.put(key, refCnt + 1);
            return true;
        }
        boolean ok = this._lock(key);
        if (!ok) {
            return false;
        }

        refs.put(key, 1);
        return true;
    }

    //可重入释放锁
    public boolean unlock(String key) {
        Map<String, Integer> refs = currentLockers();
        Integer refCnt = refs.get(key);
        if (refCnt == null) {
            return false;
        }

        refCnt = refCnt - 1;
        if ((refCnt > 0)) {
            refs.put(key, refCnt);
        } else {
            refs.remove(key);
            this._unlock(key);
        }
        return true;
    }


}

 

 

prueba

 

Como se muestra arriba: cuando un hilo Thread-14adquiere un bloqueo, puede adquirirlo varias veces. Si no se libera, el hilo principal no puede adquirir el bloqueo. Por supuesto, al escribir código, puede ajustar la estructura del código para evitar el uso de bloqueos reentrantes.

referencia:

"Los principios básicos y la práctica de citas de Redis In-Depth Adventure" -Qian Wenpin

Supongo que te gusta

Origin blog.csdn.net/wujialv/article/details/108414850
Recomendado
Clasificación