欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何鎖以及分布式鎖

如何鎖以及分布式鎖,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

為平塘等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及平塘網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、平塘網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

在多線程的軟件世界里,對(duì)共享資源的爭(zhēng)搶過程(Data Race)就是并發(fā),而對(duì)共享資源數(shù)據(jù)進(jìn)行訪問保護(hù)的最直接辦法就是引入鎖!。

無鎖編程也是一種辦法,但它不在本文的討論范圍,并發(fā)多線程轉(zhuǎn)為單線程(Disruptor),函數(shù)式編程,鎖粒度控制(ConcurrentHashMap桶),信號(hào)量(Semaphore)等手段都可以實(shí)現(xiàn)無鎖或鎖優(yōu)化。

技術(shù)上來說,鎖也可以理解成將大量并發(fā)請(qǐng)求串行化,但請(qǐng)注意串行化不能簡(jiǎn)單等同為排隊(duì) ,因?yàn)檫@里和現(xiàn)實(shí)世界沒什么不同,排隊(duì)意味著大家是公平Fair的領(lǐng)到資源,先到先得,然而很多情況下為了性能考量多線程之間還是會(huì)不公平Unfair的去搶。Java中ReentrantLock可重入鎖,提供了公平鎖和非公平鎖兩種實(shí)現(xiàn)

再注意一點(diǎn),串行也不是意味著只有一個(gè)排隊(duì)的隊(duì)伍,每次只能進(jìn)一個(gè)。當(dāng)然可以好多個(gè)隊(duì)伍,每次進(jìn)入多個(gè)。比如餐館一共10個(gè)餐桌,服務(wù)員可能一次放行最多10個(gè)人進(jìn)去,有人出來再放行同數(shù)量的人進(jìn)去。Java中Semaphore信號(hào)量,相當(dāng)于同時(shí)管理一批鎖

鎖的類型

1 自旋鎖 (Spin Lock)

自旋鎖如果已經(jīng)被別的線程獲取,調(diào)用者就一直循環(huán)在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖,”自旋”一詞就是因此而得名。

自旋鎖是一種非阻塞鎖,也就是說,如果某線程需要獲取自旋鎖,但該鎖已經(jīng)被其他線程占用時(shí),該線程不會(huì)被掛起,而是在不斷的消耗CPU的時(shí)間,不停的試圖獲取自旋鎖。

Java沒有默認(rèn)的自旋鎖實(shí)現(xiàn),示例代碼如下:

public class SpinLock {
 private AtomicReference<Thread> sign =new AtomicReference<>();
 public void lock(){
   Thread current = Thread.currentThread();
   while(!sign .compareAndSet(null, current)){
   }
 }
 public void unlock (){
   Thread current = Thread.currentThread();
   sign .compareAndSet(current, null);
 }
}

通過示例,可以看到CAS原子操作將sign從期望的null設(shè)置為當(dāng)前線程,線程A第一次調(diào)用lock()可以獲取鎖,第二次調(diào)用將進(jìn)入循環(huán)等待,因?yàn)閟ign已經(jīng)被設(shè)置為了current。
簡(jiǎn)單加個(gè)當(dāng)前鎖的owner比對(duì)判斷和鎖計(jì)數(shù)器,即可實(shí)現(xiàn)重入。

2 互斥鎖 (Mutex Lock)

互斥鎖是阻塞鎖,當(dāng)某線程無法獲取互斥鎖時(shí),該線程會(huì)被直接掛起,不再消耗CPU時(shí)間,當(dāng)其他線程釋放互斥鎖后,操作系統(tǒng)會(huì)喚醒那個(gè)被掛起的線程。

阻塞鎖可以說是讓線程進(jìn)入阻塞狀態(tài)進(jìn)行等待,當(dāng)獲得相應(yīng)的信號(hào)(喚醒,時(shí)間)時(shí),才可以進(jìn)入線程的準(zhǔn)備就緒狀態(tài),準(zhǔn)備就緒狀態(tài)的所有線程,通過競(jìng)爭(zhēng)進(jìn)入運(yùn)行狀態(tài)。它的優(yōu)勢(shì)在于,阻塞的線程不會(huì)占用 CPU 時(shí)間, 不會(huì)導(dǎo)致 CPU 占用率過高,但進(jìn)入時(shí)間以及恢復(fù)時(shí)間都要比自旋鎖略慢。在競(jìng)爭(zhēng)激烈的情況下阻塞鎖的性能要明顯高于自旋鎖。

JAVA中,能夠進(jìn)入/退出、阻塞狀態(tài)或包含阻塞鎖的方法有:
synchronized
ReentrantLock
Object.wait()/notify()
LockSupport.park()/unpart()(j.u.c經(jīng)常使用)

自旋鎖 VS 互斥鎖
兩種鎖適用于不同場(chǎng)景:
如果是多核處理器,預(yù)計(jì)線程等待鎖的時(shí)間很短,短到比線程兩次上下文切換時(shí)間要少的情況下,使用自旋鎖是劃算的。

如果是多核處理器,如果預(yù)計(jì)線程等待鎖的時(shí)間較長(zhǎng),至少比兩次線程上下文切換的時(shí)間要長(zhǎng),建議使用互斥鎖。

如果是單核處理器,一般建議不要使用自旋鎖。因?yàn)椋谕粫r(shí)間只有一個(gè)線程是處在運(yùn)行狀態(tài),那如果運(yùn)行線程發(fā)現(xiàn)無法獲取鎖,只能等待解鎖,但因?yàn)樽陨聿粧炱穑阅莻€(gè)獲取到鎖的線程沒有辦法進(jìn)入運(yùn)行狀態(tài),只能等到運(yùn)行線程把操作系統(tǒng)分給它的時(shí)間片用完,才能有機(jī)會(huì)被調(diào)度。這種情況下使用自旋鎖的代價(jià)很高。

如果加鎖的代碼經(jīng)常被調(diào)用,但競(jìng)爭(zhēng)情況很少發(fā)生時(shí),應(yīng)該優(yōu)先考慮使用自旋鎖,自旋鎖的開銷比較小,互斥量的開銷較大。

3 可重入鎖 (Reentrant Lock)

可重入鎖是一種特殊的互斥鎖,它可以被同一個(gè)線程多次獲取,而不會(huì)產(chǎn)生死鎖。

  1. 首先它是互斥鎖:任意時(shí)刻,只有一個(gè)線程鎖。即假設(shè)A線程已經(jīng)獲取了鎖,在A線程釋放這個(gè)鎖之前,B線程是無法獲取到這個(gè)鎖的,B要獲取這個(gè)鎖就會(huì)進(jìn)入阻塞狀態(tài)。

  2. 其次,它可以被同一個(gè)線程多次持有。即,假設(shè)A線程已經(jīng)獲取了這個(gè)鎖,如果A線程在釋放鎖之前又一次請(qǐng)求獲取這個(gè)鎖,那么是能夠獲取成功的。

Java中的synchronized, ReentrantLock都是可重入鎖。

4 輕量級(jí)鎖(Lightweight Lock) & 偏向鎖(Biased Lock)

首先互斥是一種會(huì)導(dǎo)致線程掛起,并在較短時(shí)間內(nèi)又需要重新調(diào)度回原線程的,較為消耗資源的操作。

Java6為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了“偏向鎖”和“輕量級(jí)鎖”,所以在Java6里鎖一共有四種狀態(tài),無鎖狀態(tài),偏向鎖狀態(tài),輕量級(jí)鎖狀態(tài)和重量級(jí)鎖狀態(tài),它會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)。鎖可以升級(jí)但不能降級(jí),意味著偏向鎖升級(jí)成輕量級(jí)鎖后不能降級(jí)成偏向鎖。這種鎖升級(jí)卻不能降級(jí)的策略,目的是為了提高獲得鎖和釋放鎖的效率。

數(shù)據(jù)庫中針對(duì)不同的鎖層級(jí)(Lock Hierarchy,表/頁/行等),
也有類似鎖升級(jí)(Lock Escalations)的理念。

5 JUC

并發(fā)大師Doug Lea在JUC包中實(shí)現(xiàn)了大量的并發(fā)工具類,并發(fā)思想在源碼中得到了很好的體現(xiàn)。比如Semaphore, CountDownLatch, CyclicBarrier都是特定場(chǎng)景下的經(jīng)典實(shí)現(xiàn),大家有興趣可以自行研究,最終一嘆: 鎖 原來可以玩出這么多花樣來。

如何鎖以及分布式鎖

java-7-concurrent-executors-uml-class-diagram-example

鎖的后遺癥

在并發(fā)世界里,鎖扮演了一個(gè)個(gè)亦正亦邪的角色,甚至很多時(shí)候是個(gè)大反派。鎖的后遺癥包括:死鎖,饑餓,活鎖,Lock Convoying(多個(gè)同優(yōu)先級(jí)的線程重復(fù)競(jìng)爭(zhēng)同一把鎖,此時(shí)大量雖然被喚醒而得不到鎖的線程被迫進(jìn)行調(diào)度切換,這種頻繁的調(diào)度切換相當(dāng)影響系統(tǒng)性能),優(yōu)先級(jí)反轉(zhuǎn),不公平和低效率等。而這些問題都是在實(shí)現(xiàn)鎖的過程中普遍存在而又不得不面對(duì)的。
這里只拋出問題讓讀者了解,具體解決方案不在本文范疇。

活鎖和死鎖的區(qū)別在于,處于活鎖的實(shí)體是在不斷的改變狀態(tài),所謂之“活”, 而處于死鎖的實(shí)體表現(xiàn)為等待;活鎖有可能自行解開,死鎖則不能。

分布式鎖

相對(duì)于單機(jī)應(yīng)用設(shè)定的單機(jī)鎖,為分布式應(yīng)用各節(jié)點(diǎn)對(duì)共享資源的排他式訪問而設(shè)定的鎖就是分布式鎖。在分布式場(chǎng)景下,有很多種情況都需要實(shí)現(xiàn)多節(jié)點(diǎn)的最終一致性。比如全局發(fā)號(hào)器,分布式事務(wù)等等。

傳統(tǒng)實(shí)現(xiàn)分布式鎖的方案一般是利用持久化數(shù)據(jù)庫(如利用InnoDB行鎖,或事務(wù),或version樂觀鎖),當(dāng)然大部分時(shí)候可以滿足大部分人的需求。而如今互聯(lián)網(wǎng)應(yīng)用的量級(jí)已經(jīng)幾何級(jí)別的爆發(fā),利用諸如zookeeper,redis等更高效的分布式組件來實(shí)現(xiàn)分布式鎖,可以提供高可用的更強(qiáng)壯的鎖特性,并且支持豐富化的使用場(chǎng)景。
開源實(shí)現(xiàn)已有不少比如Redis作者基于Redis設(shè)計(jì)的Redlock,Redission等。

小插曲:
鎖存在的地方就有爭(zhēng)議,Redlock也不例外。有一位分布式專家曾經(jīng)發(fā)表過一片文章<How to do distributed locking>, 質(zhì)疑Redlock的正確性,Redis作者則在<Is Redlock safe?>中給予了回應(yīng),爭(zhēng)鋒相對(duì)精彩無比,有興趣的讀者可以自行前往。

前人栽樹后人乘涼,當(dāng)下各種的鎖實(shí)現(xiàn)已經(jīng)給我們提供了很多優(yōu)雅的設(shè)計(jì)范本,我們具體來分析下分布式鎖到底應(yīng)該怎么設(shè)計(jì)呢?

分布式鎖的設(shè)計(jì)要點(diǎn)

我們以Redis為例,簡(jiǎn)單思考下這個(gè)鎖的實(shí)現(xiàn)。
似乎加鎖的時(shí)候只要一個(gè) SETNX 命令就搞定了,返回1代表加鎖成功,返回0 表示鎖被占用著。然后再用 DEL 命令解鎖,返回1表示解鎖成功,0表示已經(jīng)被解鎖過。
接著問題就來了:
SETNX會(huì)存在鎖競(jìng)爭(zhēng),如果在執(zhí)行過程中客戶端宕機(jī),會(huì)引起死鎖問題,也就是鎖資源無法釋放。解決死鎖的問題其實(shí)可以可以向MySQL的死鎖檢測(cè)學(xué)習(xí),設(shè)置一個(gè)失效時(shí)間,通過key的時(shí)間戳來判斷是否需要強(qiáng)制解鎖。
但是強(qiáng)制解鎖也存在問題,一個(gè)就是時(shí)間差問題,不同的機(jī)器的本地時(shí)間可能也存在時(shí)間差,在很小事務(wù)粒度的高并發(fā)場(chǎng)景下還是會(huì)存在問題,比如刪除鎖的時(shí)候,會(huì)判斷時(shí)間戳已經(jīng)超過時(shí)效,有可能刪除其他已經(jīng)獲取鎖的客戶端的鎖。
另外,如果設(shè)置了一個(gè)超時(shí)時(shí)間,若程序執(zhí)行時(shí)間超過了超時(shí)時(shí)間,那么還沒執(zhí)行完鎖會(huì)被自動(dòng)釋放,原來持鎖的客戶端再次解鎖的時(shí)候會(huì)出現(xiàn)問題,而且最為嚴(yán)重的還是一致性沒有得到保障。如何合理的設(shè)置這個(gè)超時(shí)時(shí)間可能是一個(gè)觀測(cè)并不斷調(diào)整的過程。

那么,總結(jié)下設(shè)計(jì)的幾個(gè)要點(diǎn):

  • 鎖的時(shí)效。避免單點(diǎn)故障造成死鎖,影響其他客戶端獲取鎖。但是也要保證一旦一個(gè)客戶端持鎖,在客戶端可用時(shí)不會(huì)被其他客戶端解鎖。

  • 持鎖期間的check。盡量在關(guān)鍵節(jié)點(diǎn)檢查鎖的狀態(tài),所以要設(shè)計(jì)成可重入鎖。

  • 減少獲取鎖的操作,盡量減少redis壓力。所以需要讓客戶端的申請(qǐng)鎖有一個(gè)等待時(shí)間,而不是所有申請(qǐng)鎖的請(qǐng)求線程不斷的循環(huán)申請(qǐng)鎖。

  • 加鎖的事務(wù)或者操作盡量粒度小,減少其他客戶端申請(qǐng)鎖的等待時(shí)間,提高處理效率和并發(fā)性。

  • 持鎖的客戶端解鎖后,要能通知到其他等待鎖的節(jié)點(diǎn),否則其他節(jié)點(diǎn)只能一直等待一個(gè)預(yù)計(jì)的時(shí)間再觸發(fā)申請(qǐng)鎖。類似線程的notifyAll,要能同步鎖狀態(tài)給其他客戶端,并且是分布式消息。

  • 考慮任何執(zhí)行句柄中可能出現(xiàn)的異常,狀態(tài)的正確流轉(zhuǎn)和處理。比如,不能因?yàn)橐粋€(gè)節(jié)點(diǎn)解鎖失敗,或者鎖查詢失?。╮edis 超時(shí)或者其他運(yùn)行時(shí)異常),影響整個(gè)等待的任務(wù)隊(duì)列,或者任務(wù)池。

  • 若Redis服務(wù)器宕機(jī)或者網(wǎng)絡(luò)異常,要有其他備份方案,比如單機(jī)鎖限流+最終數(shù)據(jù)庫的持久化鎖來做好最終一致性控制。

看完上述內(nèi)容,你們掌握如何鎖以及分布式鎖的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

分享名稱:如何鎖以及分布式鎖
當(dāng)前URL:http://aaarwkj.com/article34/iiogpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、品牌網(wǎng)站制作企業(yè)建站、響應(yīng)式網(wǎng)站網(wǎng)站設(shè)計(jì)公司、

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司
性色av人妻中文一区二区| 老熟女露脸吞精一二三四区| 最近更新中文字幕不卡在线| 国产精品大全中文字幕| 亚洲三级黄片免费播放| 三级日本一区二区三区| 91九色中文视频在线观看| 亚洲精品成人午夜av| 久久久国产精品免费看| 麻豆乱淫一区二区三爱免费| 欧美 日韩一区二区在线| 亚洲国模av一区二区三区| 亚洲精品日韩国产av| 麻豆精品国产一区二区91| 日韩精品在线观看视频一区二区三区| 成人免费亚洲av在线| 日韩av熟女中文字幕| 欧美日韩三级国产在线| 亚洲精品影视一区二区| 丁香婷婷麻豆激情综合网| 国产一区二区成人精品| 男人天堂av一区二区| 91久久久久久人妻精品粉嫩| 亚洲成人永久免费精品| 欧美中日韩一区二区三区| 99久久夜国产精品| 日韩高清在线亚洲专区不卡| 久久亚洲精品国产精品黑人| 又爽又色的日本网站| 日日夜夜天天操天天干| 一区二区三区深夜福利| 国产精品自在线拍亚洲另类| 中文字幕人妻丝袜乱一区二区| 国产亚洲一区激情小说| 禁止18观看视频软件| 国产精品偷伦一区二区| 亚洲乱码国产乱码精品| 丰满少妇被激烈的插进去| 精品一区二区在线欧美日韩| 麻豆一区二区人妻网站| 国产免费很黄很色视频|