來(lái)源:騰訊云 時(shí)間:2023-04-21 16:35:39
(相關(guān)資料圖)
在此之前,去看了下Redission的實(shí)現(xiàn)原理,不過(guò)在開(kāi)發(fā)中,原本的代碼使用RedistTemplate實(shí)現(xiàn)的,也不太想換,所以我想了下,不如自己實(shí)現(xiàn)要給WatchDog。
我的想法是,在用戶加上鎖的時(shí)候開(kāi)啟個(gè)定時(shí)任務(wù)線程,并且在定時(shí)任務(wù)中,判斷原線程isAlive狀態(tài)進(jìn)行“續(xù)命”。
下面是代碼(在這里面為了方便,未使用的是HuTool.CornUtil來(lái)實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)):
/** * Title * * @ClassName: LockUtil * @Description:鎖工具類(lèi),通過(guò)內(nèi)部枚舉類(lèi)實(shí)現(xiàn)單例,防止反射攻擊 * @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; /** * 帶看門(mén)狗機(jī)制上鎖 * @param lockObj * @return */ public boolean DistributedLock(Object lockObj){ try { return DistributedLock(lockObj,null,null); } catch (KaToolException e) { throw new RuntimeException(e); } } @Resource LockConfig lockConfig; //加鎖 /** * 無(wú)看門(mén)狗機(jī)制上鎖 * @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); //實(shí)現(xiàn)看門(mén)狗 if (isDelay){ if (LockUtil.isOpenCorn==false){ //如果同一個(gè)項(xiàng)目之前打開(kāi)過(guò),那么先關(guān)閉,避免重復(fù)啟動(dòng) CronUtil.stop(); //支持秒級(jí)別定時(shí)任務(wù) CronUtil.setMatchSecond(true); //定時(shí)服務(wù)啟動(dòng) 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); } //利用枚舉類(lèi)實(shí)現(xiàn)單例模式,枚舉類(lèi)屬性為靜態(tài)的 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; }}
標(biāo)簽:
下一篇:最后一頁(yè)
針對(duì)RedisTemplate分布式鎖實(shí)現(xiàn)WatchDog_全球今日?qǐng)?bào)
Python面向?qū)ο缶幊?魔術(shù)方法-__call__和__getattr__方法
使用 Spring Cloud Bus 在微服務(wù)之間傳遞消息示例_天天熱門(mén)
go的數(shù)據(jù)類(lèi)型-其他數(shù)據(jù)類(lèi)型-channel(二) 全球滾動(dòng)
黑龍江省公立醫(yī)院種牙要降價(jià)了
當(dāng)前關(guān)注:冷熱大逆轉(zhuǎn)!武漢氣溫打?qū)φ郏€有連續(xù)大風(fēng)陰雨天
支持三地創(chuàng)建國(guó)家級(jí)車(chē)聯(lián)網(wǎng)先導(dǎo)區(qū) 滲透率逐步提升
支持三地創(chuàng)建國(guó)家級(jí)車(chē)聯(lián)網(wǎng)先導(dǎo)區(qū)滲透率逐步提升
熱文:湖北省宣恩縣發(fā)布大風(fēng)藍(lán)色預(yù)警
湖北省宣恩縣發(fā)布大風(fēng)藍(lán)色預(yù)警
環(huán)球快資訊:三六零(601360)4月20日主力資金凈買(mǎi)入8.00億元
截至2023年4月20日收盤(pán),三六零(601360)報(bào)收于16 86元,上漲6 1%,換手率7 51%,成交...
易方達(dá)戰(zhàn)略新興產(chǎn)業(yè)股票型證券投資基金暫停申購(gòu)、轉(zhuǎn)換轉(zhuǎn)入及定期定額投資業(yè)務(wù)的公告 環(huán)球熱訊
1 公告基本信息基金名稱(chēng)易方達(dá)戰(zhàn)略新興產(chǎn)業(yè)股票型證券投資基金基金簡(jiǎn)稱(chēng)易方達(dá)戰(zhàn)略新興產(chǎn)...
使用 Spring Cloud Bus 在微服務(wù)之間傳遞消息示例_天天熱門(mén)