溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中怎么實(shí)現(xiàn)悲觀鎖與樂(lè)觀鎖

發(fā)布時(shí)間:2021-06-30 17:23:13 來(lái)源:億速云 閱讀:129 作者:Leah 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)Java中怎么實(shí)現(xiàn)悲觀鎖與樂(lè)觀鎖,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

悲觀鎖

假設(shè)會(huì)發(fā)生并發(fā)沖突;在整個(gè)數(shù)據(jù)處理過(guò)程中,將數(shù)據(jù)處于鎖定狀態(tài)。 獨(dú)占鎖是一種悲觀鎖,synchronized就是一種獨(dú)占鎖,它假設(shè)最壞的情況,并且只有在確保其它線程不會(huì)造成干擾的情況下執(zhí)行,會(huì)導(dǎo)致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。

樂(lè)觀鎖

假設(shè)不會(huì)發(fā)生并發(fā)沖突;處理數(shù)據(jù)時(shí)不加鎖,如果處理失敗產(chǎn)生沖突就重試,直到成功為止。 當(dāng)數(shù)據(jù)爭(zhēng)用不嚴(yán)重時(shí),樂(lè)觀鎖效果更好。比如CAS就是一種樂(lè)觀鎖思想的應(yīng)用。

互斥同步/阻塞同步(悲觀策略)

同步是指在多個(gè)線程并發(fā)訪問(wèn)共享數(shù)據(jù)時(shí),保證共享數(shù)據(jù)在同一個(gè)時(shí)刻只被一個(gè)(或者是一些,使用信號(hào)量的時(shí)候)線程使用。 臨界區(qū)(CriticalSection)、互斥量(Mutex)和信號(hào)量(Semaphore)都是主要的互斥實(shí)現(xiàn)方式。

synchronized

synchronized是Java中基本的互斥同步手段,synchronized關(guān)鍵字經(jīng)過(guò)編譯之后,會(huì)在同步塊的前后分別形成monitorenter和monitorexit這兩個(gè)字節(jié)碼指令,這兩個(gè)字節(jié)碼都需要一個(gè)reference類型的參數(shù)來(lái)指明要鎖定和解鎖的對(duì)象。如果Java程序中的synchronized明確指定了對(duì)象參數(shù),那就是這個(gè)對(duì)象的reference;如果沒(méi)有明確指定,那就根據(jù)synchronized修飾的是實(shí)例方法還是類方法,去取對(duì)應(yīng)的對(duì)象實(shí)例或Class對(duì)象來(lái)作為鎖對(duì) 象。

ReentrantLock

重入鎖(ReentrantLock)是JDK1.5中JUC提供的另一種互斥同步手段,在基本用法上,ReentrantLock與synchronized很相似,他們都具備一樣的線程重入特性,只是代碼寫(xiě)法上有點(diǎn)區(qū)別,一個(gè)表現(xiàn)為API層面的互斥鎖(lock()和unlock()方法配合try/finally語(yǔ)句塊來(lái)完成),另一個(gè)表現(xiàn)為原生語(yǔ)法層面的互斥鎖。不過(guò),相比synchronized,ReentrantLock增加了一些高級(jí)功能,主要有以下3項(xiàng):等待可中斷、可實(shí)現(xiàn)公平鎖,以及鎖可以綁定多個(gè)條件。

等待可中斷

等待可中斷是指當(dāng)持有鎖的線程長(zhǎng)期不釋放鎖的時(shí)候,正在等待的線程可以選擇放棄等待,改為處理其他事情,可中斷特性對(duì)處理執(zhí)行時(shí)間非常長(zhǎng)的同步塊很有幫助。

公平鎖

公平鎖是指多個(gè)線程在等待同一個(gè)鎖時(shí),必須按照申請(qǐng)鎖的時(shí)間順序來(lái)依次獲得鎖;而非公平鎖則不保證這一點(diǎn),在鎖被釋放時(shí),任何一個(gè)等待鎖的線程都有機(jī)會(huì)獲得鎖。 synchronized中的鎖是非公平的,ReentrantLock默認(rèn)情況下也是非公平的,但可以通過(guò)帶布爾值的構(gòu)造函數(shù)要求使用公平鎖。

綁定多個(gè)條件

鎖綁定多個(gè)條件是指一個(gè)ReentrantLock對(duì)象可以同時(shí)綁定多個(gè)Condition對(duì)象,而在synchronized中,鎖對(duì)象的wait()和notify()或notifyAll()方法可以實(shí)現(xiàn)一個(gè)隱含的條件,如果要和多于一個(gè)的條件關(guān)聯(lián)的時(shí)候,就不得不額外地添加一個(gè)鎖,而ReentrantLock則無(wú)須這樣做,只需要多次調(diào)用newCondition()方法即可。

非阻塞同步(樂(lè)觀策略)

互斥同步最主要的問(wèn)題就是進(jìn)行線程阻塞和喚醒所帶來(lái)的性能問(wèn)題,因此這種同步也稱為阻塞同步(Blocking Synchronization)。 非阻塞同步是一種不需要把線程掛起的樂(lè)觀的并發(fā)策略,先進(jìn)行操作,如果沒(méi)有其他線程爭(zhēng)用共享數(shù)據(jù),那操作就成功了;如果共享數(shù)據(jù)有爭(zhēng)用,產(chǎn)生了沖突,那就再采取其他的補(bǔ)償措施(最常見(jiàn)的補(bǔ)償措施就是不斷地重試,直到成功為止)。

比較并交換CAS(Compare-and-Swap)

CAS指令需要有3個(gè)操作數(shù),分別是內(nèi)存位置(在Java中可以簡(jiǎn)單理解為變量的內(nèi)存地址,用V表示)、舊的預(yù)期值(用A表示)和新值(用B表示)。CAS指令執(zhí)行時(shí),當(dāng)且僅當(dāng)V符合舊預(yù)期值A(chǔ)時(shí),處理器用新值B更新V的值,否則它就不執(zhí)行更新,但是無(wú)論是否更新了V的值,都會(huì)返回V的舊值,上述的處理過(guò)程是一個(gè)原子操作。 JDK1.5之后,Java程序中才可以使用CAS操作,該操作由sun.misc.Unsafe類里面的 compareAndSwapInt()和compareAndSwapLong()等幾個(gè)方法包裝提供,虛擬機(jī)在內(nèi)部對(duì)這些方法做了特殊處理,即時(shí)編譯出來(lái)的結(jié)果就是一條平臺(tái)相關(guān)的處理器CAS指令,沒(méi)有方法調(diào)用的過(guò)程,或者可以認(rèn)為是無(wú)條件內(nèi)聯(lián)進(jìn)去了

ABA問(wèn)題

如果一個(gè)變量V初次讀取的時(shí)候是A值,并且在準(zhǔn)備賦值的時(shí)候檢查到它仍然為A值,那我們就能說(shuō)它的值沒(méi)有被其他線程改變過(guò)了嗎?如果在這段期間它的值曾經(jīng)被改成了B,后來(lái)又被改回為A,那CAS操作就會(huì)誤認(rèn)為它從來(lái)沒(méi)有被改變過(guò)。 J.U.C包為了解決這個(gè)問(wèn)題,提供了一個(gè)帶有標(biāo)記的原子引用類”AtomicStampedReference”,它可以通過(guò)控制變量值的版本來(lái)保證CAS的正確性。 大部分情況下ABA問(wèn)題不會(huì)影響程序并發(fā)的正確性,如果需要解決ABA問(wèn)題,改用傳統(tǒng)的互斥同步可能會(huì)比原子類更高效。

關(guān)于Java中怎么實(shí)現(xiàn)悲觀鎖與樂(lè)觀鎖就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI