2020Java面試題最新(五鎖機制篇)

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