1. Redis分布式锁实现原理
分布式锁本质上要实现的目标就是在Redis里面占一个“茅坑”,当别的进程也要来占时,发现已经有人蹲在那里了,就只好放弃或者稍后再试。占坑一般是使用setnx(set if not exists)指令,只允许被一个客户端占坑。先来先占,用完了,再调用del指令释放茅坑。
死锁问题:如果逻辑执行到中间出现异常了,可能会导致del指令没有被调用,这样就会陷入死锁,锁永远得不到释放,解决这个问题我们在拿到锁之后,再给锁加上一个过期时间,比如 5s,这样即使中间出现异常也可以保证 5 秒之后锁会自动释放。
2. 普通非阻塞锁实现
2.1 存在问题
如果某一个进程没有拿到锁得到了false的结果那么次进程是否执行当前任务?显然对于一般情况来说我们的任务都是必须执行的那么此时我们就要考虑该何时执行了,在传统的锁中我们如果没有拿到锁线程就进入了阻塞状态那么此处我们是否可以改进同样实现阻塞唤醒机制。
3. 分布式阻塞锁具体实现
3.1 解决思路
(1)首先我们改造lock锁,当不能创建key时就利用当前key阻塞当前线程
(2)当某一个线程释放锁时通过redis的pub/sub发送一个消息消息内容为key
(3)所有使用锁的应用监听lock通道的消息,在收到消息时通过key唤醒对应线程
3.2具体实现
package com.hgy.common.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import java.util.HashMap;
public class RedisLock extends JedisPubSub {
//是否已经初始化监听
private static volatile boolean isListen = false;
//每一个redis的key对应一个阻塞对象
private HashMap blockers = new HashMap<>();
private Jedis jedis;
//当前获得锁的线程
private Thread curThread;
public RedisLock(Jedis jedis) {
this.jedis = jedis;
//保证没一个应用只初始化一次监听
if (!isListen) {
synchronized (RedisLock.class) {
if (!isListen) {
// 启动一个线程做消息监听
new Thread