Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >针对RedisTemplate分布式锁实现WatchDog

针对RedisTemplate分布式锁实现WatchDog

原创
作者头像
Karos
修改于 2023-04-16 05:23:10
修改于 2023-04-16 05:23:10
7980
举报
文章被收录于专栏:MyBlog-KarosMyBlog-Karos

在此之前,去看了下Redission的实现原理,不过在开发中,原本的代码使用RedistTemplate实现的,也不太想换,所以我想了下,不如自己实现要给WatchDog。

我的想法是,在用户加上锁的时候开启个定时任务线程,并且在定时任务中,判断原线程isAlive状态进行“续命”。

下面是代码(在这里面为了方便,未使用的是HuTool.CornUtil来实现动态定时任务):

代码语言:java
AI代码解释
复制
/**
 * Title
 *
 * @ClassName: LockUtil
 * @Description:锁工具类,通过内部枚举类实现单例,防止反射攻击
 * @author: Karos
 * @date: 2023/1/4 0:17
 * @Blog: https://www.wzl1.top/
 */

package cn.katool.lock;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.katool.Config.LockConfig;
import cn.katool.Exception.ErrorCode;
import cn.katool.Exception.KaToolException;
import cn.katool.other.MethodIntefaceUtil;
import com.qiniu.util.StringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Component
@Scope("prototype")
@Slf4j
public class LockUtil {
        @Resource
        RedisTemplate redisTemplate;
        private LockUtil(){

        }
        private static boolean isOpenCorn=false;

        /**
         * 带看门狗机制上锁
         * @param lockObj
         * @return
         */
        public boolean DistributedLock(Object lockObj){
                try {
                        return DistributedLock(lockObj,null,null);
                } catch (KaToolException e) {
                        throw new RuntimeException(e);
                }
        }
        @Resource
        LockConfig lockConfig;
        //加锁

        /**
         * 无看门狗机制上锁
         * @param obj
         * @param exptime
         * @param timeUnit
         * @return
         * @throws KaToolException
         */
        public boolean DistributedLock(Object obj,Long exptime,TimeUnit timeUnit) throws KaToolException {
                if (ObjectUtil.isEmpty(obj)){
                        throw new KaToolException(ErrorCode.PARAMS_ERROR," Lock=> 传入obj为空");
                }
                Boolean isDelay=false;
                if (ObjectUtil.isAllEmpty(exptime,timeUnit)){
                        isDelay=true;
                }
                if(ObjectUtil.isEmpty(exptime)){
                        exptime= lockConfig.getInternalLockLeaseTime();;
                }
                if (ObjectUtils.isEmpty(timeUnit)){
                        timeUnit=lockConfig.getTimeUnit();
                }
                //线程被锁住了,就一直等待
                DistributedAssert(obj);
                Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("Lock:"+obj.toString(), "1", exptime, timeUnit);
                log.info("katool=> LockUntil => DistributedLock:{} value:{} extime:{} timeUnit:{}",obj.toString(), "1", exptime, timeUnit);
                //实现看门狗
                if (isDelay){
                        if (LockUtil.isOpenCorn==false){
                                //如果同一个项目之前打开过,那么先关闭,避免重复启动
                                CronUtil.stop();
                                //支持秒级别定时任务
                                CronUtil.setMatchSecond(true);
                                //定时服务启动
                                CronUtil.start();
                                LockUtil.isOpenCorn=true;
                        }
                        Thread thread = Thread.currentThread();
                        TimeUnit finalTimeUnit = timeUnit;
                        Long finalExptime = exptime;
                        class TempClass{
                                public String scheduleId;
                        }
                        final TempClass tempClass = new TempClass();
                        tempClass.scheduleId=CronUtil.schedule("0/30 * * * * ?", new Task() {
                                @SneakyThrows
                                @Override
                                public void execute() {
                                        boolean alive = thread.isAlive();
                                        if (alive) {
                                                delayDistributedLock(obj, finalExptime>=3?(finalExptime / 3):finalExptime, finalTimeUnit);
                                                return;
                                        } else {
                                                if (tempClass.scheduleId==null||"".equals(tempClass.scheduleId)){
                                                        return;
                                                }
                                                CronUtil.remove(tempClass.scheduleId);
                                                DistributedUnLock(obj);
                                                return;
                                        }
                                }
                        });
                }
                return BooleanUtil.isTrue(aBoolean);
        }

        //检锁
        public void DistributedAssert(Object obj) throws KaToolException {
                if (ObjectUtils.isEmpty(obj)){
                        throw new KaToolException(ErrorCode.PARAMS_ERROR," Lock=> 传入obj为空");
                }
                while(true){
                        Object o = redisTemplate.opsForValue().get("Lock:" + obj.toString());
                        if (ObjectUtils.isEmpty(o))return;
                }
        }

        //延期
        public boolean delayDistributedLock(Object obj,Long exptime,TimeUnit timeUnit) throws KaToolException {
                if (ObjectUtils.isEmpty(obj)){
                        throw new KaToolException(ErrorCode.PARAMS_ERROR," Lock=> 传入obj为空");
                }
                Boolean aBoolean = redisTemplate.opsForValue().setIfPresent("Lock:"+obj.toString(), "1", exptime, timeUnit);
                log.info("katool=> LockUntil => delayDistributedLock:{} value:{} extime:{} timeUnit:{}",obj.toString(), "1", exptime, timeUnit);
                return BooleanUtil.isTrue(aBoolean);
        }
        //释放锁
        public boolean DistributedUnLock(Object obj) throws KaToolException {
                if (ObjectUtils.isEmpty(obj)){
                        throw new KaToolException(ErrorCode.PARAMS_ERROR," Lock=> 传入obj为空");
                }
                Boolean aBoolean = redisTemplate.delete("Lock:" + obj.toString());
                log.info("katool=> LockUntil => unDistributedLock:{} isdelete:{} ",obj.toString(),true);
                return BooleanUtil.isTrue(aBoolean);
        }



        //利用枚举类实现单例模式,枚举类属性为静态的
        private enum SingletonFactory{
                Singleton;
                LockUtil lockUtil;
                private SingletonFactory(){
                        lockUtil=new LockUtil();
                }
                public LockUtil getInstance(){
                        return lockUtil;
                }
        }
        @Bean("LockUtil")
        public static LockUtil getInstance(){
                return SingletonFactory.Singleton.lockUtil;
        }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【掌印日记-点赞功能实现】使用Redis实现分布式锁
在项目开发中,点赞事件频率较高,我们不可能直接将对点赞功能的操作放到MySQL里面,所以我们引入Redis中间件。
Karos
2023/01/16
1.2K0
重新说说Redis实现分布式公平可重入锁的实现,这次具体说说异步唤醒机制,这次带上QPS检测
但是这样做会有一点问题,我们每次休眠的时间都是固定的,仍然会有一大部分空窗期,我设置30s的锁过期,那么好,20个线程足足跑了两三分钟,这个效率绝对不行,对吧。
Karos
2023/09/13
8971
重新说说Redis实现分布式公平可重入锁的实现,这次具体说说异步唤醒机制,这次带上QPS检测
RedisTemplate分布式锁演变、Redission分布式锁实现!
来源 | https://blog.csdn.net/zhangkaixuan456/article/details/110679617
程序猿DD
2021/09/03
1.4K0
Java基于redis实现分布式锁(SpringBoot)
分布式锁,其实原理是就是多台机器,去争抢一个资源,谁争抢成功,那么谁就持有了这把锁,然后去执行后续的业务逻辑,执行完毕后,把锁释放掉。
Happyjava
2024/02/02
7130
Java基于redis实现分布式锁(SpringBoot)
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
开发一个高并发预约管理处理系统,其中用户可以预约倾听者。由于并发预约可能导致冲突和混乱,需要实现分布式锁来确保同一时间段只有一个用户可以进行预约。为了实现这一目的,使用Redis作为分布式锁的存储介质,并设计一组表来存储倾听者的预约情况。
苏泽
2024/03/01
6650
分布式锁+AOP实现缓存
  随着业务中缓存及分布式锁的加入,业务代码变的复杂起来,除了需要考虑业务逻辑本身,还要考虑缓存及分布式锁的问题,增加了程序员的工作量及开发难度。而缓存的玩法套路特别类似于事务,而声明式事务就是用了aop的思想实现的。
别团等shy哥发育
2023/04/23
3030
分布式锁+AOP实现缓存
基于Redis实现分布式锁
基于Redis实现分布式锁 一. 基本原理 基于Redis的setnx命令,如果设置成功,则表示当前进程(线程)获取锁成功,否则说明有其他进程已经获取了锁,需进行等待 setnx 的key为需要加锁的资源名称(实例中为方法名),value为业务唯一的id 加锁时需制定锁的过期时间,避免锁未正常释放而导致的死锁问题 加锁时需设置等待超时时间,避免等待时间过长导致系统性能下降 释放锁时,与Redis中的value与当前的业务id进行对比,符合才执行释放操作 二. 代码实现 加锁的核心操作 /** * @Au
张申傲
2020/09/03
3540
redis命令和lua实现分布式锁
因为这个命令的性质,多个线程竞争时只有一个线程能修改key的值。利用这一点可以实现锁的互斥功能。
HUC思梦
2020/09/03
1.6K0
【110期】面试官:Redis分布式锁如何解决锁超时问题?
关于redis分布式锁, 查了很多资料, 发现很多只是实现了最基础的功能, 但是, 并没有解决当锁已超时而业务逻辑还未执行完的问题, 这样会导致: A线程超时时间设为10s(为了解决死锁问题), 但代码执行时间可能需要30s, 然后redis服务端10s后将锁删除, 此时, B线程恰好申请锁, redis服务端不存在该锁, 可以申请, 也执行了代码, 那么问题来了, A、B线程都同时获取到锁并执行业务逻辑, 这与分布式锁最基本的性质相违背: 在任意一个时刻, 只有一个客户端持有锁, 即独享。
良月柒
2021/01/07
9170
【110期】面试官:Redis分布式锁如何解决锁超时问题?
「分布式」实现分布式锁的正确姿势
最近看到好多博主都在推分布式锁,实现方式很多,基于db、redis、zookeeper。zookeeper方式实现起来比较繁琐,这里我们就谈谈基于redis实现分布式锁的正确实现方式。
一个程序员的成长
2020/11/25
8700
「分布式」实现分布式锁的正确姿势
Redis实现分布式锁
一看就会的超详细教程:SpringBoot整合MybatisPlus!>>> 1.自己实现 private static String REDIS_LOCK = "redis_lock";
用户5927264
2021/06/08
3840
Redis实现分布式锁
redis实现分布式锁工具类 灰常好用
public interface RedisDistributionLock { /** * 加锁成功,返回加锁时间 * @param lockKey * @param threadName * @return */ public long lock(String lockKey, String threadName); /** * 解锁, 需要更新加锁时间,判断
陈灬大灬海
2023/05/12
5640
Java基于redis实现分布式锁(SpringBoot)
分布式锁,其实原理是就是多台机器,去争抢一个资源,谁争抢成功,那么谁就持有了这把锁,然后去执行后续的业务逻辑,执行完毕后,把锁释放掉。
Happyjava
2019/07/17
5940
Java基于redis实现分布式锁(SpringBoot)
基于redis的分布式锁二种应用场景
“分布式锁”是用来解决分布式应用中“并发冲突”的一种常用手段,实现方式一般有基于zookeeper及基于redis二种。具体到业务场景中,我们要考虑二种情况:
菩提树下的杨过
2019/06/17
1.1K0
基于redis的分布式锁二种应用场景
纠正误区:这才是 SpringBoot Redis 分布式锁的正确实现方式
在单机部署的时候,我们可以使用 Java 中提供的 JUC 锁机制避免多线程同时操作一个共享变量产生的安全问题。JUC 锁机制只能保证同一个 JVM 进程中的同一时刻只有一个线程操作共享资源。
码哥字节
2024/01/29
1.4K0
纠正误区:这才是 SpringBoot Redis 分布式锁的正确实现方式
ZooKeeper 分布式锁实现
#1 场景描述# 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程共享了一些资源, 可能就需要分布式锁来锁定对这些资源的访问。 #2 思路# 进程需要访问共享数据时, 就在"/locks"节点下创建一个sequence类型的子节点, 称为thisPath. 当thisPath在所有子节点中最小时, 说明该进程获得了锁. 进程获得锁之后, 就可以访问共享资源了. 访问完成后, 需要将thisPath删除. 锁由新的最小的子节点获得.
用户1263954
2018/06/22
6750
SpringBoot实现Redis分布式锁
分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本文介绍基于Redis实现分布式锁。
Ant丶
2022/03/01
5290
浅谈缓存与分布式锁
对于一个大型网站而言,每天的访问量是巨大的,尤其遇到某些特定的时间点,比如电商平台的购物节、教育平台开学季。当在某个时间点遇到过量的并发时,往往会压垮服务器导致网站崩溃,因此,网站对于高并发的处理是至关重要的,其中缓存起着举足轻重的作用。对于一些不经常变化,或者热度很高的数据,可以将其存入缓存,此时当用户访问时将直接读取缓存而不查询数据库,从而大大提高了网站的吞吐量。
wangweijun
2022/01/10
2100
SpringBoot-Redis 实现分布式锁
大多数互联网系统都是分布式部署的,分布式部署确实能带来性能和效率上的提升,但为此,我们就需要多解决一个分布式环境下,数据一致性的问题。
周三不加班
2019/09/03
5.8K0
SpringBoot系列之基于Jedis实现分布式锁
在单机环境,我们使用最多的是juc包里的单机锁,但是随着微服务分布式项目的普及,juc里的锁是不能控制分布锁环境的线程安全的,因为单机锁只能控制同个进程里的线程安全,不能控制多节点的线程安全,所以就需要使用分布式锁
SmileNicky
2023/12/13
1.5K0
SpringBoot系列之基于Jedis实现分布式锁
推荐阅读
相关推荐
【掌印日记-点赞功能实现】使用Redis实现分布式锁
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档