全球聚焦:针对RedisTemplate分布式锁实现WatchDog
(资料图片仅供参考)
在此之前,去看了下Redission的实现原理,不过在开发中,原本的代码使用RedistTemplate实现的,也不太想换,所以我想了下,不如自己实现要给WatchDog。
我的想法是,在用户加上锁的时候开启个定时任务线程,并且在定时任务中,判断原线程isAlive状态进行“续命”。
下面是代码(在这里面为了方便,未使用的是HuTool.CornUtil来实现动态定时任务):
/** * 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")@Slf4jpublic 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; }}
关键词:
- 融侨集团1-7月多批次社区如约交付,全年预计交付户数1.3万
- 女童不慎掉入20米深井 18岁小姨三次下井成功营救
- 西安3个区域12月28日起每日开展全员核酸 官方提倡民众居家健身
- 浙江乐清一核酸检测结果异常人员 复采复检为阴性
- 浙江本轮疫情报告确诊病例490例 提倡“双节”非必要不出省
- 西安警方通报6起涉疫违法案件
- 西安新一轮核酸筛查日检测能力达160万管
- 西安市累计报告本土确诊病例811例
- 重庆曝光4起违反中央八项规定精神典型问题 警示党员干部清新过节
- 云南清水河边检站查获走私玉石和玉石毛料65公斤
-
重庆曝光4起违反中央八项规定精神典型问题 警示党员干部清新过节
新华社重庆12月28日电(记者李松)元旦、春节临近,重庆市纪委监委在28日公开曝光4起违反中央八项规定精神典型问题,提醒警示党员干部清
-
云南清水河边检站查获走私玉石和玉石毛料65公斤
中新网临沧12月28日电 (徐媛 雷珍玉)记者28日从云南清水河出入境边防检查站获悉,该站近日在清水河口岸查获一起利用货车藏匿走私玉石
-
吉林市政协原党组成员、副主席孙洪彬被开除党籍和公职
中央纪委国家监委网站讯 据吉林省纪委监委消息:日前,经吉林省委批准,吉林省纪委监委对吉林市政协原党组成员、副主席孙洪彬严重违纪
-
陕西延安新增2例确诊病例 活动轨迹公布
陕西延安新增2例确诊病例 活动轨迹公布→ 今日(28日),陕西延安市举行新冠肺炎疫情防控新闻发布会。会上介绍,截至2021年12月28日
-
陕西延安公布新划定中风险地区
12月28日,陕西延安市举行新冠肺炎疫情防控新闻发布会。 为了进一步强化辖区疫情防控工作,延安市宝塔区应对疫情指挥部出台了五条防
-
陕西延安新增2例本土确诊病例 均在宝塔区
今日(28日),陕西延安市举行新冠肺炎疫情防控新闻发布会。 会上介绍,截至2021年12月28日,延安市新增本土确诊病例2例,均在宝塔区
-
西安累计报告本土确诊病例811例
今天(12月28日)下午,西安市召开疫情防控新闻发布会,介绍疫情防控最新进展。 会上通报,2021年12月27日0时-24时,西安市新增本土
-
西安疫情的八个关键问题,专家这么研判
这几天,西安的疫情牵动着全国人民的心。12月27日,西安市新增确诊病例175例。从12月9日0时到12月27日24时,本轮西安全市累计报告本土
-
向家暴说“不 ” 山西各方联动打通反家暴“最后一公里”
中新网太原12月28日电 题:向家暴说“不” 山西各方联动打通反家暴“最后一公里” 作者 吴琼 高瑞峰 赵娟 “对于家庭暴力
-
让农民工不再忧“薪” 湖南祁阳高效根治欠薪
中新网永州12月28日电 (刘志军 周盛波)“感谢你们,没有你们不辞辛苦、多次讨要,我们肯定拿不着钱,这个年肯定过不好。”27日,农民
X 关闭
7月重点城市二手房成交环比下降16% 新房成交同比转负
南宁水源地环境问题提前清零 以高质量饮水安全促进乡村振兴
西安新增本土确诊病例150例 详情发布
广东最低气温跌至-6℃现冰挂 部分道路及海上交通受影响
“2022科学跨年系列活动”启动 提高公众对科学类流言“免疫力”
X 关闭
天天信息:欧联杯:罗马晋级四强
当前热门:如何煮扁豆
天天快报!今日看点|国新办举行一季度外汇收支数据新闻发布会
全球观点:阳台鱼菜共生设备受追捧
世界通讯!马力刺客|混动车上马力机 被刺竟是我自己