高可用的redis分布式锁

1:一个分布式锁具备哪些条件

 1:互斥性:只能有一个线程可以获取到锁
 2:锁超时:在超过规定时间自动释放锁,防止死锁
 3:支持阻塞和非阻塞:在一次没有获取锁的时候回重复尝试获得锁,而不是直接返回失败
 4:可重入性:在一个锁中可以再去获得锁
 5:高可用: 在超过我们设定的锁过期的时间,但是我们的线程还没有执行完操作,还没有释放锁,就被过期释放了。所以要提供
            可以自动续期的机制

具体见代码,代码中有注释



public class RedisLock {

    private StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();

    private ThreadLocal<String> threadLocal = new ThreadLocal<>();

    /**
     * 加锁
     */
    public Boolean lock(String key,Long timeOut,TimeUnit unit) {

        //加个判断  在同一个线程中threadLock中有值得话,就是表明该该线程已经获取过锁了,我们直接返回true ,保证锁的可重入性
        if (threadLocal.get() == null) {
            //新启动一个线程,没个10s给锁加过期时间,防止业务时间超过过期时间
            Thread addThread =  new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        stringRedisTemplate.expire(key,timeOut,unit);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            addThread.start();


            String uuid = addThread.getId() +":"+ UUID.randomUUID().toString();
            threadLocal.set(uuid);

            //在redis中插入一条key  超时时间为30s  把添加过期时间的线程id也作为key  后面我们通过id 在释放锁的时候停止该线程
            Boolean isLock = stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, timeOut, unit);

            //支持阻塞性  获取锁失败 重复去获取锁
            if (!isLock) {
                while (true) {
                    isLock = stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, timeOut, unit);
                    if (isLock) {
                        break;
                    }
                }
            }

            return isLock;
        } else {
            return true;
        }


    }

    /**
     * 解锁
     */
    public Boolean release(String key) {

        //加一个线程id 判断,防止其他线程业务锁释放掉其他业务的锁
        if (threadLocal.get().equals(stringRedisTemplate.opsForValue().get(key))) {
            //获取延期的线程id  停止该线程
            String s = stringRedisTemplate.opsForValue().get(key);
            String[] split = s.split(":");
            Thread thread = findThread(Long.parseLong(split[0]));
            thread.interrupt();
            //释放锁
            stringRedisTemplate.delete(key);
            //释放线程id
            threadLocal.remove();//防止线程复用  释放锁
        }
        return null;
    }

    /**
     * 通过线程id获得线程
     *
     * @param threadId
     * @return
     */
    public static Thread findThread(long threadId) {
        ThreadGroup group = Thread.currentThread().getThreadGroup();
        while(group != null) {
            Thread[] threads = new Thread[(int)(group.activeCount() * 1.2)];
            int count = group.enumerate(threads, true);
            for(int i = 0; i < count; i++) {
                if(threadId == threads[i].getId()) {
                    return threads[i];
                }
            }
            group = group.getParent();
        }
        return null;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值