2020Java面試題最新(五鎖機(jī)制篇)
鎖的原因都是由并發(fā)問題發(fā)生的,在此我只是寫一些面試中可能會(huì)問到的問題以及問題的答案,并不是給大家深入的講解鎖機(jī)制
一般面試官問都是從一個(gè)點(diǎn)引入一個(gè)點(diǎn)的問問題,所以我就先從線程問題引入到鎖問題
1.說(shuō)說(shuō)線程安全問題
線程安全是多線程領(lǐng)域的問題,線程安全可以簡(jiǎn)單理解為一個(gè)方法或者一個(gè)實(shí)例可以在多線程環(huán)境中使用而不會(huì)出現(xiàn)問題
在 Java 多線程編程當(dāng)中,提供了多種實(shí)現(xiàn) Java 線程安全的方式:
- 最簡(jiǎn)單的方式,使用 Synchronization 關(guān)鍵字
- 使用 java.util.concurrent.atomic 包中的原子類,例如 AtomicInteger
- 使用 java.util.concurrent.locks 包中的鎖
- 使用線程安全的集合 ConcurrentHashMap
- 使用 volatile 關(guān)鍵字,保證變量可見性(直接從內(nèi)存讀,而不是從線程 cache 讀)
2.volatile 實(shí)現(xiàn)原理
- 在 JVM 底層 volatile 是采用“內(nèi)存屏障”來(lái)實(shí)現(xiàn)的
- 緩存一致性協(xié)議(MESI協(xié)議)它確保每個(gè)緩存中使用的共享變量的副本是一致的。其核心思想如下:當(dāng)某個(gè) CPU 在寫數(shù)據(jù)時(shí),如果發(fā)現(xiàn)操作的變量是共享變量,則會(huì)通知其他 CPU 告知該變量的緩存行是無(wú)效的,因此其他 CPU 在讀取該變量時(shí),發(fā)現(xiàn)其無(wú)效會(huì)重新從主存中加載數(shù)據(jù)
3.synchronize 實(shí)現(xiàn)原理
同步代碼塊是使用 monitorenter 和 monitorexit 指令實(shí)現(xiàn)的,同步方法(在這看不出來(lái)需要看 JVM 底層實(shí)現(xiàn))依靠的是方法修飾符上的 ACC_SYNCHRONIZED 實(shí)現(xiàn)
4.synchronized 與 lock 的區(qū)別
synchronized 和 lock 的用法區(qū)別
- synchronized(隱式鎖):在需要同步的對(duì)象中加入此控制,synchronized 可以加在方法上,也可以加在特定代碼塊中,括號(hào)中表示需要鎖的對(duì)象
- lock(顯示鎖):需要顯示指定起始位置和終止位置。一般使用 ReentrantLock 類做為鎖,多個(gè)線程中必須要使用一個(gè) ReentrantLock 類做為對(duì)象才能保證鎖的生效。且在加鎖和解鎖處需要通過 lock() 和 unlock() 顯示指出。所以一般會(huì)在 finally 塊中寫 unlock() 以防死鎖
synchronized 和 lock 性能區(qū)別
synchronized 是托管給 JVM 執(zhí)行的,而 lock 是 Java 寫的控制鎖的代碼。在 JDK 1.5 中,synchronize 是性能低效的。因?yàn)檫@是一個(gè)重量級(jí)操作,需要調(diào)用操作接口,導(dǎo)致有可能加鎖消耗的系統(tǒng)時(shí)間比加鎖以外的操作還多。相比之下使用 Java 提供的 Lock 對(duì)象,性能更高一些。但是到了 JDK 1.6,發(fā)生了變化。synchronize 在語(yǔ)義上很清晰,可以進(jìn)行很多優(yōu)化,有適應(yīng)自旋,鎖消除,鎖粗化,輕量級(jí)鎖,偏向鎖等等。導(dǎo)致在 JDK 1.6 上 synchronize 的性能并不比 Lock 差
synchronized 和 lock 機(jī)制區(qū)別
- synchronized 原始采用的是 CPU 悲觀鎖機(jī)制,即線程獲得的是獨(dú)占鎖。獨(dú)占鎖意味著其 他線程只能依靠阻塞來(lái)等待線程釋放鎖
- Lock 用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設(shè)沒有沖突而去完成某項(xiàng)操作,如果因?yàn)闆_突失敗就重試,直到成功為止。樂觀鎖實(shí)現(xiàn)的機(jī)制就是 CAS 操作(Compare and Swap)
由此面試官就可能下一個(gè)問題就接入到鎖的問題上,當(dāng)然也可能前面的問題回答不上,引入不到鎖上,但是面試官想問時(shí)會(huì)主動(dòng)問到吧
5.說(shuō)說(shuō)悲觀鎖
悲觀鎖悲觀的認(rèn)為每一次操作都會(huì)造成更新丟失問題,在每次查詢時(shí)加上排他鎖
每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖
6.說(shuō)說(shuō)常用的 CAS 樂觀鎖
CAS 是項(xiàng)樂觀鎖技術(shù),當(dāng)多個(gè)線程嘗試使用 CAS 同時(shí)更新同一個(gè)變量時(shí),只有其中一個(gè)線程能更新變量的值,而其它線程都失敗,失敗的線程并不會(huì)被掛起,而是被告知這次競(jìng)爭(zhēng)中失敗,并可以再次嘗試
CAS 操作包含三個(gè)操作數(shù) —— 內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。如果內(nèi)存位置的值與預(yù)期原值相匹配,那么處理器會(huì)自動(dòng)將該位置值更新為新值。否則,處理器不做任何操作。無(wú)論哪種情況,它都會(huì)在 CAS 指令之前返回該位置的值。(在 CAS 的一些特殊情況下將僅返回 CAS 是否成功,而不提取當(dāng)前值。)CAS 有效地說(shuō)明了“我認(rèn)為位置 V 應(yīng)該包含值 A;如果包含該值,則將 B 放到這個(gè)位置;否則,不要更改該位置,只告訴我這個(gè)位置現(xiàn)在的值即可。”這其實(shí)和樂觀鎖的沖突檢查 + 數(shù)據(jù)更新的原理是一樣的
每次查詢都不會(huì)造成更新丟失,利用版本字段控制
7.說(shuō)說(shuō) CAS ‘ABA’ 問題
CAS 算法實(shí)現(xiàn)一個(gè)重要前提需要取出內(nèi)存中某時(shí)刻的數(shù)據(jù),而在下時(shí)刻比較并替換,那么在這個(gè)時(shí)間差類會(huì)導(dǎo)致數(shù)據(jù)的變化
比如說(shuō)一個(gè)線程 one 從內(nèi)存位置 V 中取出 A,這時(shí)候另一個(gè)線程 two 也從內(nèi)存中取出 A,并且 two 進(jìn)行了一些操作變成了 B,然后 two 又將 V 位置的數(shù)據(jù)變成 A,這時(shí)候線程 one 進(jìn)行 CAS 操作發(fā)現(xiàn)內(nèi)存中仍然是 A,然后 one 操作成功。盡管線程 one 的 CAS 操作成功,但是不代表這個(gè)過程就是沒有問題的
部分樂觀鎖的實(shí)現(xiàn)是通過版本號(hào)(version)的方式來(lái)解決 ABA 問題,樂觀鎖每次在執(zhí)行數(shù)據(jù)的修改操作時(shí),都會(huì)帶上一個(gè)版本號(hào),一旦版本號(hào)和數(shù)據(jù)的版本號(hào)一致就可以執(zhí)行修改操作并對(duì)版本號(hào)執(zhí)行 +1 操作,否則就執(zhí)行失敗。因?yàn)槊看尾僮鞯陌姹咎?hào)都會(huì)隨之增加,所以不會(huì)出現(xiàn) ABA 問題,因?yàn)榘姹咎?hào)只會(huì)增加不會(huì)減少
8.樂觀鎖的業(yè)務(wù)場(chǎng)景及實(shí)現(xiàn)方式
樂觀鎖(Optimistic Lock):
- 每次獲取數(shù)據(jù)的時(shí)候,都不會(huì)擔(dān)心數(shù)據(jù)被修改,所以每次獲取數(shù)據(jù)的時(shí)候都不會(huì)進(jìn)行加鎖,但是在更新數(shù)據(jù)的時(shí)候需要判斷該數(shù)據(jù)是否被別人修改過。如果數(shù)據(jù)被其他線程修改,則不進(jìn)行數(shù)據(jù)更新,如果數(shù)據(jù)沒有被其他線程修改,則進(jìn)行數(shù)據(jù)更新。由于數(shù)據(jù)沒有進(jìn)行加鎖,期間該數(shù)據(jù)可以被其他線程進(jìn)行讀寫操作
- 比較適合讀取操作比較頻繁的場(chǎng)景,如果出現(xiàn)大量的寫入操作,數(shù)據(jù)發(fā)生沖突的可能性就會(huì)增大,為了保證數(shù)據(jù)的一致性,應(yīng)用層需要不斷的重新獲取數(shù)據(jù),這樣會(huì)增加大量的查詢操作,降低了系統(tǒng)的吞吐量
8.簡(jiǎn)單講講自旋鎖
自旋鎖是采用讓當(dāng)前線程不停地的在循環(huán)體內(nèi)執(zhí)行實(shí)現(xiàn)的,當(dāng)循環(huán)的條件被其他線程改變時(shí) 才能進(jìn)入臨界區(qū)
當(dāng)一個(gè)線程 調(diào)用這個(gè)不可重入的自旋鎖去加鎖的時(shí)候沒問題,當(dāng)再次調(diào)用lock()的時(shí)候,因?yàn)樽孕i的持有引用已經(jīng)不為空了,該線程對(duì)象會(huì)誤認(rèn)為是別人的線程持有了自旋鎖
使用了CAS原子操作,lock函數(shù)將owner設(shè)置為當(dāng)前線程,并且預(yù)測(cè)原來(lái)的值為空。unlock函數(shù)將owner設(shè)置為null,并且預(yù)測(cè)值為當(dāng)前線程。
當(dāng)有第二個(gè)線程調(diào)用lock操作時(shí)由于owner值不為空,導(dǎo)致循環(huán)一直被執(zhí)行,直至第一個(gè)線程調(diào)用unlock函數(shù)將owner設(shè)置為null,第二個(gè)線程才能進(jìn)入臨界區(qū)。
由于自旋鎖只是將當(dāng)前線程不停地執(zhí)行循環(huán)體,不進(jìn)行線程狀態(tài)的改變,所以響應(yīng)速度更快。但當(dāng)線程數(shù)不停增加時(shí),性能下降明顯,因?yàn)槊總€(gè)線程都需要執(zhí)行,占用CPU時(shí)間。如果線程競(jìng)爭(zhēng)不激烈,并且保持鎖的時(shí)間段。適合使用自旋鎖
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
三年經(jīng)驗(yàn)網(wǎng)易、滴滴、點(diǎn)我Java崗面試經(jīng)驗(yàn)匯總
這篇文章主要介紹了三年經(jīng)驗(yàn)網(wǎng)易、滴滴、點(diǎn)我Java崗面試經(jīng)驗(yàn)匯總,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-06-12- 本文是小編給大家收藏整理的關(guān)于java基礎(chǔ)面試題小結(jié),在面試中經(jīng)常會(huì)被問題,今天小編特此整理把內(nèi)容分享到腳本之家平臺(tái),需要的朋友參考下吧2020-05-19
史上最全阿里Java面試題目大匯總(強(qiáng)烈建議收藏)
這篇文章主要介紹了史上最全阿里Java面試題目大匯總,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-05-08- 這篇文章主要介紹了最全Java面試208題,涵蓋大廠必考范圍,熟悉本文中列出的知識(shí)點(diǎn)會(huì)大大增加通過前兩輪技術(shù)面試的幾率,感興趣的可以了解一下2020-05-07
- 這篇文章主要介紹了2020年最新版Java面試題大全,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-04-16
- 這篇文章主要介紹了100+經(jīng)典Java面試題及答案解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)2020-04-09
面試百度、阿里、騰訊,這134道Java面試題你會(huì)多少
這篇文章主要介紹了面試百度、阿里、騰訊,這134道Java面試題你會(huì)多少,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-03-26
這篇文章主要介紹了85道Java微服務(wù)面試題整理,助力2020面試 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-03-13
最新115道華為、京東、滴滴、美團(tuán)精選Java面試題整理
這篇文章主要介紹了最新115道華為、京東、滴滴、美團(tuán)精選Java面試題整理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-03-042萬(wàn)字Java并發(fā)編程面試題整理(含答案,建議收藏)
這篇文章主要介紹了2萬(wàn)字Java并發(fā)編程面試題整理(含答案,建議收藏),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2020-02-13



