分布式鎖的實例應(yīng)用

前篇:Redis+Lua實現(xiàn)分布式鎖

場景描述:

更新一個頁面信息寡润,首先更新頁面在導(dǎo)航中的信息,然后刪除頁面下所有圖表的組件以及配置等詳細(xì)信息并保存新頁面的所有圖表信息饵较。

注:下列方法存在于在前篇:Redis+Lua實現(xiàn)分布式鎖

類:LockSerice.java

1.方法lock(String lock, int expire)?:獲取鎖

2.方法softUnlock(String lock):解鎖树叽,只有當(dāng)鎖過期時才會解鎖

3.方法hardUnlock(String lock):解鎖靴跛,不關(guān)心鎖的是否過期

4.方法getLockStatus(String lock):獲取鎖的狀態(tài)

5.方法autoIncrLock(String lock):鎖的值自加1诊霹,如果鎖本身不存在羞延,默認(rèn)從0開始

6.方法autoDecrLock(String lock):鎖的值自減1,如果鎖本身不存在脾还,默認(rèn)從0開始

7.方法softUnlockAuto(String lock):解鎖伴箩,只有當(dāng)鎖過期時才會解鎖

8.方法hardUnlockAuto(String lock):解鎖,不關(guān)心當(dāng)前鎖的狀態(tài)

9.方法getLockStatusAuto(String lock):獲取鎖的狀態(tài)

說明:下面提到的對線程的鎖和頁面的鎖使用了相同的lock鄙漏,但是在放入緩存前會加前綴嗤谚,所有,盡管線程的鎖和頁面的鎖顯示的lock一樣泥张,但是實際上不同呵恢,后續(xù)不在對此做贅述鞠值。以下代碼只是上述問題的邏輯展現(xiàn)媚创,沒有實現(xiàn)細(xì)節(jié)以及異常問題處理,參考時請注意彤恶!


一钞钙、getPageInfo(?Long pageId)

獲取頁面信息:現(xiàn)獲取頁面鎖,然后再獲取線程鎖(若拿不到稍微等一會)声离,如果實在等不到(很可能已經(jīng)掛了)芒炼,就從緩存中讀取備份的數(shù)據(jù)。


PageInfo getPageInfo ( Long pageId) throws Exception {

? ? Assert.isTrue(getLockForWait(lock, 2), "頁面正在更新术徊,請稍后重試...");? ?

? ? PageInfo pageInfo;

? ? try {

? ? ? ? if(!getThreadLockForWait(lock, 2)){

? ??????????pageInfo = ##從Redis中獲取備份的數(shù)據(jù)##;

? ??????} else {

? ? ? ??? ??pageInfo =?##從數(shù)據(jù)庫中獲取數(shù)據(jù)##;

? ? ? ? }

? ? } finally {

? ??????lockService.hardUnlock(lock);

????}

? ? return pageInfo;

}


二本刽、getLockForWait(String lock, int expire)

獲取頁面的鎖,如果拿不到鎖赠涮,就稍微等一會子寓,如果實在等不到就算了。


private boolean getLockForWait(String lock, int expire) throws Exception {

??? ????boolean status;

? ?? ???int count =5 * expire;

? ??? ??while (!(status = getLock(lock)) && count >0) {

? ??????????????Thread.sleep(200);

? ? ? ??? ??????count--;

??? ??? }

? ??????return status;

}


三笋除、getThreadLockForWait(String?threadLock, int expire)

獲取線程的鎖斜友,如果拿到了,就清除上次的備份數(shù)據(jù)垃它。返回true

如果拿不到鲜屏,稍微等一會,實在等不到国拇,強制解鎖洛史,返回false。這種情況還需要在進(jìn)步一處理酱吝,目前還沒有想好方案虹菲。


public boolean getThreadLockForWait(String threadLock, int expire) throws Exception {

? ? int count =5 * expire;

? ? while (!lockService.getLockStatusAuto(threadLock) && count >0) {

????????count--;

? ? ? ? Thread.sleep(200);

? ? }

????if (lockService.softUnlockAuto(threadLock)) {

? ? ? ? ? ? ##do:刪除緩存中備份的數(shù)據(jù)##

????????????return true;

? ? } else {

????????????lockService.hardUnlockAuto(lock);

????????????return false;

? ? }

}


三、updatePageInfo(PageInfo pageInfo)

更新頁面掉瞳,先獲取頁面的鎖毕源,拿到之后浪漠,再判斷之前保存該頁面時的線程是否已經(jīng)執(zhí)行完成,如果沒有執(zhí)行完就稍微等一會霎褐,如果實在等不到址愿,則在緩存在備份一份數(shù)據(jù)。


Long updatePageInfo(PageInfo pageInfo) throws Exception {

? ? ? ? Long pageId = pageInfo.getId();

? ? ? ? if(lockService.lock(lock, expire)) {

????????????????updateMenuInfo(pageInfo);

????????????????deletePageInfo(pageId);//刪除頁面配置必須放在更新導(dǎo)航之后冻璃,如有疑問可留言

? ????????? ????updatePageInfo(pageId, pageInfo);?

? ? ? ? ? ? ? ? tryBackups(lock, pageInfo);

? ? ? ? ? ??? ??lockService.hardUnlock(lock);

????????}

}


四响谓、?tryBackups(String lock, PageInfo pageInfo)

嘗試備份,如果線程執(zhí)行完成則直接返回true省艳。若線程尚未執(zhí)行完娘纷,則等待幾秒(這個方法可以拋出一個線程去執(zhí)行),如果線程在規(guī)定等待時間內(nèi)一直未能完成跋炕,則進(jìn)行備份赖晶。


public void tryBackups(String lock, PageInfo pageInfo) {

? ? ? ? int count =100;

? ? ? ? while (!lockService.softUnlockAuto(lock) && count >0) {

????????????count--;

? ? ? ? ? ? Thread.sleep(200);

? ? ? ? }

? ? ? ?if(!lockService.softUnlockAuto(lock)) {

? ? ? ? ? ? do:在緩存中做備份,可設(shè)定過期時間為1天

? ??????}

}


五辐烂、deletePageInfo(final Long pageId)

刪除頁面遏插,以多線程的方式刪除,并記錄線程的狀態(tài)


void deletePageInfo(final Long pageId) throws Exception {

????final String lock = String.valueOf(pageId);

????List<ChartInfo> chartInfos = getChartInfos(pageId);

????for (ChartInfo chartInfo : chartInfos) {

????????fixedThreadPool.execute(new Runnable() {

????????????@Override

????????????public void run() {

????????????????autoIncrLock(lock);?

????????????????deleteChartInfo(pageId);

????????????????autoDecrLock(lock);

? ? ? ?}}}}

? ? deletePageInfo(pageId);

}


六纠修、updatePageInfo(final Long pageId, PageInfo pageInfo)

保存頁面中的圖表信息胳嘲,以多線程的方式執(zhí)行,并記錄線程的狀態(tài)


void updatePageInfo(final Long pageId, PageInfo pageInfo) throws Exception{

? ? if(pageId != null){

? ? ? ? final String lock = String.valueOf(pageId);

? ? ? ? if(CollectionUtils.isNotEmpty(pageInfo)){

? ? ? ? ? ? for(final CharInfo chartInfo : pageInfo){

????????????????fixedThreadPool.execute(new Runnable() {? ??????????

????????????????????@Override

? ? ????????????????public void run() {

????????????????????????????????autoIncrLock(lock);?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateChartInfo(pageId);?

????????????????????????????????autoDecrLock(lock);? ? ? ? ? ? ? ? ? ? ? ? ??

? ??}}}}}}


問題總結(jié):

分布式鎖在使用過程中需要特別注意不同鎖之前的嵌套扣草,防止產(chǎn)生死鎖了牛。

多線程在使用過程中,要注意并發(fā)是否對線程執(zhí)行狀態(tài)有影響辰妙。

上述提到的實例中鹰祸,鎖的粒度一共有3種。

第一種為站點級別的鎖上岗,防止導(dǎo)航菜單并發(fā)帶來的問題福荸。

第二種為頁面級別的鎖,防止頁面并發(fā)帶來的問題肴掷。

第三類是線程級別的鎖敬锐,主要是為了多線程的情況下,存在未完成線程帶來的問題呆瞻。

其中台夺,線程的鎖最容易產(chǎn)生問題,因此增加了簡單的容錯機制痴脾,當(dāng)線程的鎖不能釋放時颤介,做了相應(yīng)的等待以及備份處理。頁面更新時,頁面被鎖滚朵,其他任何進(jìn)程均不允許修改以及獲取該頁面的信息冤灾,以免獲取的信息不完整以及相互覆蓋的問題。當(dāng)頁面被讀取時(此處應(yīng)該做一下調(diào)整辕近,頁面讀取時韵吨,應(yīng)該允許其他線程讀取,但是不允許更新)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末移宅,一起剝皮案震驚了整個濱河市归粉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌漏峰,老刑警劉巖糠悼,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浅乔,居然都是意外死亡倔喂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門童擎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滴劲,“玉大人攻晒,你說我怎么就攤上這事顾复。” “怎么了鲁捏?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵芯砸,是天一觀的道長。 經(jīng)常有香客問我给梅,道長假丧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任动羽,我火速辦了婚禮包帚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘运吓。我一直安慰自己渴邦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布拘哨。 她就那樣靜靜地躺著谋梭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倦青。 梳的紋絲不亂的頭發(fā)上瓮床,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音,去河邊找鬼隘庄。 笑死踢步,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丑掺。 我是一名探鬼主播贾虽,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吼鱼!你這毒婦竟也來了蓬豁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤菇肃,失蹤者是張志新(化名)和其女友劉穎地粪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琐谤,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡蟆技,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斗忌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片质礼。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖织阳,靈堂內(nèi)的尸體忽然破棺而出眶蕉,到底是詐尸還是另有隱情,我是刑警寧澤唧躲,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布造挽,位于F島的核電站,受9級特大地震影響弄痹,放射性物質(zhì)發(fā)生泄漏饭入。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一肛真、第九天 我趴在偏房一處隱蔽的房頂上張望谐丢。 院中可真熱鬧,春花似錦蚓让、人聲如沸乾忱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饭耳。三九已至,卻和暖如春执解,著一層夾襖步出監(jiān)牢的瞬間寞肖,已是汗流浹背纲酗。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留新蟆,地道東北人觅赊。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像琼稻,于是被迫代替她去往敵國和親吮螺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容