悲觀鎖和樂觀鎖_面試必備之樂觀鎖與悲觀鎖

1afed7e611c6b9b979e31f9c34311867.png

何謂悲觀鎖與樂觀鎖

樂觀鎖對應于生活中樂觀的人總是想著事情往好的方向發展,悲觀鎖對應于生活中悲觀的人總是想著事情往壞的方向發展。這兩種人各有優缺點,不能不以場景而定說一種人好于另外一種人。

大家可以點擊加群【JAVA架構知識學習討論群】473984645,(如多你想跳槽換工作,但是技術又不夠,或者工作遇到了瓶頸,我這里有一個Java的免費直播課程,講的是高端的知識點,只要有1-5年的開發工作經驗可以加群找我要課堂鏈接。)注意:是免費的 沒有開發經驗的誤入。

悲觀鎖

總是假設最壞的情況,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉讓給其它線程)。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨占鎖就是悲觀鎖思想的實現。

樂觀鎖

總是假設最好的情況,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號機制和CAS算法實現。樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量,像數據庫提供的類似于write_condition機制,其實都是提供的樂觀鎖。在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS實現的。

兩種鎖的使用場景

從上面對兩種鎖的介紹,我們知道兩種鎖各有優缺點,不可認為一種好于另一種,像樂觀鎖適用于寫比較少的情況下(多讀場景),即沖突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果是多寫的情況,一般會經常產生沖突,這就會導致上層應用會不斷的進行retry,這樣反倒是降低了性能,所以一般多寫的場景下用悲觀鎖就比較合適。

樂觀鎖常見的兩種實現方式

樂觀鎖一般會使用版本號機制或CAS算法實現。

1. 版本號機制

一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛才讀取到的version值為當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

舉一個簡單的例子:

假設數據庫中帳戶信息表中有一個 version 字段,當前值為 1 ;而當前帳戶余額字段( balance )為 $100 。當需要對賬戶信息表進行更新的時候,需要首先讀取version字段。

操作員 A 此時將其讀出( version=1 ),并從其帳戶余額中扣除 $50( $100-$50 )。

在操作員 A 操作的過程中,操作員B 也讀入此用戶信息( version=1 ),并從其帳戶余額中扣除 $20 ( $100-$20 )。

操作員 A 完成了修改工作,提交更新之前會先看數據庫的版本和自己讀取到的版本是否一致,一致的話,就會將數據版本號加1( version=2 ),連同帳戶扣除后余額( balance=$50 ),提交至數據庫更新,此時由于提交數據版本大于數據庫記錄當前版本,數據被更新,數據庫記錄 version 更新為 2 。

操作員 B 完成了操作,提交更新之前會先看數據庫的版本和自己讀取到的版本是否一致,但此時比對數據庫記錄版本時發現,操作員 B 提交的數據版本號為 2 ,而自己讀取到的版本號為1 ,不滿足 “ 當前最后更新的version與操作員第一次讀取的版本號相等 “ 的樂觀鎖策略,因此,操作員 B 的提交被駁回。

這樣,就避免了操作員 B 用基于 version=1 的舊數據修改的結果覆蓋操作員A 的操作結果的可能。

2. CAS算法

即compare and swap(比較與交換),是一種有名的無鎖算法。無鎖編程,即不使用鎖的情況下實現多線程之間的變量同步,也就是在沒有線程被阻塞的情況下實現變量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三個操作數

  • 需要讀寫的內存值 V
  • 進行比較的值 A
  • 擬寫入的新值 B

當且僅當 V 的值等于 A時,CAS通過原子方式用新值B來更新V的值,否則不會執行任何操作(比較和替換是一個原子操作)。一般情況下是一個自旋操作,即不斷的重試

樂觀鎖的缺點

ABA 問題是樂觀鎖一個常見的問題

1 ABA 問題

如果一個變量V初次讀取的時候是A值,并且在準備賦值的時候檢查到它仍然是A值,那我們就能說明它的值沒有被其他線程修改過了嗎?很明顯是不能的,因為在這段時間它的值可能被改為其他值,然后又改回A,那CAS操作就會誤認為它從來沒有被修改過。這個問題被稱為CAS操作的 "ABA"問題。

JDK 1.5 以后的 AtomicStampedReference 類就提供了此種能力,其中的 compareAndSet 方法就是首先檢查當前引用是否等于預期引用,并且當前標志是否等于預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。

2 循環時間長開銷大

自旋CAS(也就是不成功就一直循環執行直到成功)如果長時間不成功,會給CPU帶來非常大的執行開銷。 如果JVM能支持處理器提供的pause指令那么效率會有一定的提升,pause指令有兩個作用,第一它可以延遲流水線執行指令(de-pipeline),使CPU不會消耗過多的執行資源,延遲的時間取決于具體實現的版本,在一些處理器上延遲時間是零。第二它可以避免在退出循環的時候因內存順序沖突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush),從而提高CPU的執行效率。

3 只能保證一個共享變量的原子操作

CAS 只對單個共享變量有效,當操作涉及跨多個共享變量時 CAS 無效。但是從 JDK 1.5開始,提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個變量放在一個對象里來進行 CAS 操作.所以我們可以使用鎖或者利用AtomicReference類把多個共享變量合并成一個共享變量來操作。

CAS與synchronized的使用情景

簡單的來說CAS適用于寫比較少的情況下(多讀場景,沖突一般較少),synchronized適用于寫比較多的情況下(多寫場景,沖突一般較多)

對于資源競爭較少(線程沖突較輕)的情況,使用synchronized同步鎖進行線程阻塞和喚醒切換以及用戶態內核態間的切換操作額外浪費消耗cpu資源;而CAS基于硬件實現,不需要進入內核,不需要切換線程,操作自旋幾率較少,因此可以獲得更高的性能。

對于資源競爭嚴重(線程沖突嚴重)的情況,CAS自旋的概率會比較大,從而浪費更多的CPU資源,效率低于synchronized。

補充: Java并發編程這個領域中synchronized關鍵字一直都是元老級的角色,很久之前很多人都會稱它為 “重量級鎖” 。但是,在JavaSE 1.6之后進行了主要包括為了減少獲得鎖和釋放鎖帶來的性能消耗而引入的 偏向鎖 和 輕量級鎖 以及其它各種優化之后變得在某些情況下并不是那么重了。synchronized的底層實現主要依靠 Lock-Free 的隊列,基本思路是 自旋后阻塞,競爭切換后繼續競爭鎖,稍微犧牲了公平性,但獲得了高吞吐量。在線程沖突較少的情況下,可以獲得和CAS類似的性能;而線程沖突嚴重的情況下,性能遠高于CAS。

c45ecb70597df722f4c7c90a460919a2.png

我這兒整理了比較全面的JAVA相關的面試資料,

需要領取面試資料的同學,請加群:473984645

b9ddc1389e31cc40b8167be99f35310e.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446019.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Microsoft Visual Studio2019環境下搭建FFmpeg開發環境

參考鏈接 《基于 FFmpeg SDL 的視頻播放器的制作》課程的視頻_雷霄驊的博客-CSDN博客_雷霄驊ffmpeg視頻教程小學期課程資料 - 基于FFmpegSDL的視頻播放器的制作.zip_免費高速下載|百度網盤-分享無限制輔助參考鏈接使用VS2019創建項目,添加文件和庫地址_MY CUP OF …

vue process.env獲取不到_從文檔開始,重學vue(下)源碼級別

此篇文章主要是從應用及源碼層面講解vue部分常用api,閱讀起來可能略有難度,新手可以看《從文檔開始,重學vue(上)》示例代碼均在vue-cli3中完成Vue.extend()可以使用 extend 創建一個子類,該方法通常用于構建全局組件,如彈框組件等,下面我們就用它來制作個全局alert組件吧首先我…

Microsoft Visual Studio2019環境下搭建SDL開發環境

參考鏈接 《基于 FFmpeg SDL 的視頻播放器的制作》課程的視頻_雷霄驊的博客-CSDN博客_雷霄驊ffmpeg視頻教程小學期課程資料 - 基于FFmpegSDL的視頻播放器的制作.zip_免費高速下載|百度網盤-分享無限制輔助參考鏈接VS自動鏈接到Windows上隨vcpkg安裝的SDL2庫 | 碼農俱樂部 - G…

不關注公眾號可以獲取openid嗎_微信公眾號粉絲遷移

目錄 [toc] 微信公眾號遷移 正常的公眾號遷移直接通過微信操作就可以,如下圖。但是因為udb數據里面存的是遷移前公眾號的openid以及unionid,需要自行獲取新舊openid以及unionid。 舊的用戶信息要在遷移之前獲取,第三步點擊同意之后就公眾號的接口就調不通…

建筑專業規范大全 2020版_房屋建筑工程現行規范標準目錄匯編(2020版)—建筑電氣...

房屋建筑工程現行規范標準目錄匯編(2020版)建筑電氣規范編號規范名稱GB 50034-2013建筑照明設計標準GB 50052-2009供配電系統設計規范GB 50053-201320kV及以下變電所設計規范GB 50057-2010建筑物防雷設計規范GB 50147-2010電氣裝置安裝工程 高壓電器施工及驗收規范GB 50148-201…

基于Microsoft Visual Studio2019環境編寫ffmpeg視頻解碼代碼

舊代碼 舊代碼使用了很多過時的API,這些API使用后,vs會報編譯器警告 (級別 3) C4996的錯誤即 函數被聲明為已否決 報 C4996的錯誤 // test_ffmpeg.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。 // #define SDL_MAIN_HANDLED …

16進制轉double dotnet_終于把計算機進制弄明白了!

And theres one thing that I need from you我只需要你為我做一-件事Can you come through, through待在我的身邊就好Through, yeah你可以撫慰一切不滿And theres one thing that I need from you你可以過來Can you come through?待在我的身邊嗎-comethruJeremy Zucker進制進制…

FFmpeg源代碼簡單分析-架構圖-解碼

參考鏈接 FFmpeg源代碼結構圖 - 解碼_雷霄驊的博客-CSDN博客_ffmpeg雷霄驊函數背景色 函數在圖中以方框的形式表現出來。不同的背景色標志了該函數不同的作用: 粉紅色背景函數:FFmpeg的API函數。白色背景的函數:FFmpeg的內部函數。黃色背景…

JUnit單元測試筆記

#01 JUnit簡介 1.在項目工程中的Library,add 一個JUnit的Jar包,按需要添加JUnit 3 或 JUnit 4(分為被測試類與測試類較佳)。 2.單元測試是由程序員完成的。 3.Java 5 之前的版本只能 用JUnit 4前的版本(因為JUnit 4用到Java 5的…

jqery獲取每個月天數_三年級《年、月、日》單元重要知識點整理匯總,以及難點題型解析...

昨天給大家分享了《計算經過的時間》問題,今天給大家分享的是《年、月、日》單元中重要的幾個知識點,以及難點題型解析。知識點1 感知年、月、日一、結合生活實際,看看下面事情需要經過多少時間。跑完100米大約需要經過十幾(秒)。2.打一場籃球…

FFmpeg源代碼簡單分析-架構圖-編碼

參考鏈接 FFmpeg源代碼結構圖 - 編碼_雷霄驊的博客-CSDN博客_ffmpeg 源碼函數背景色 函數在圖中以方框的形式表現出來。不同的背景色標志了該函數不同的作用: 粉紅色背景函數:FFmpeg的API函數。白色背景的函數:FFmpeg的內部函數。黃色背景的…

為革命,保護視力——為Eclipse更換暗黑皮膚及編輯頁面的字體顏色主題

1.在Eclipse中的菜單欄的Help -> Eclipse Market 的 Search欄中輸入 Eclipse Moonrise UI Theme ,之后自己執生啦(確保上網配置正確)。 2.與上面操作類似,輸入 Eclipse Color Theme,選擇安裝。 3.選擇菜單欄的Win…

python函數可以作為容器對象嗎_正確理解Python函數是第一類對象

正確理解 Python函數,能夠幫助我們更好地理解 Python 裝飾器、匿名函數(lambda)、函數式編程等高階技術。函數(Function)作為程序語言中不可或缺的一部分,太稀松平常了。但函數作為第一類對象(First-Class Object)卻是 Python 函數的一大特性。那到底什么…

FFmpeg源代碼簡單分析-通用- av_register_all()

參考鏈接 ffmpeg 源代碼簡單分析 : av_register_all()_雷霄驊的博客-CSDN博客_av_register_all()從學齡前開始解讀FFMPEG代碼 之 avcodec_register_all函數_zzyincsdn的博客-CSDN博客

@suppressWarnings(unchecked)及其相關屬性在Java中意思

首先suppressWarnings("unchecked")是JDK1.5中新加入的Annotation語法,用來壓制警告信息的。 編寫代碼時,有時會提示一些警告(例如:使用已經廢棄的類,沒有加入泛型等),如果不想讓程序…

FFmpeg源代碼簡單分析-通用-avcodec_register_all()

參考鏈接 ffmpeg 源代碼簡單分析 : avcodec_register_all()_雷霄驊的博客-CSDN博客

pythonsklearn乳腺癌數據集_Python的Sklearn庫中的數據集

一、Sklearn介紹scikit-learn是Python語言開發的機器學習庫,一般簡稱為sklearn,目前算是通用機器學習算法庫中實現得比較完善的庫了。其完善之處不僅在于實現的算法多,還包括大量詳盡的文檔和示例。其文檔寫得通俗易懂,完全可以當…

FFmpeg源代碼簡單分析-通用- 內存的分配和釋放(av_malloc()、av_free()等)

參考鏈接 FFmpeg源代碼簡單分析:內存的分配和釋放(av_malloc()、av_free()等)_雷霄驊的博客-CSDN博客_av_malloc 內容介紹 內存操作的常見函數位于libavutil\mem.c中本文記錄最常使用的幾個函數: av_malloc()av_realloc()av_mal…

面試題——死鎖的實現

public class DeadLock {public static Object Chopstick_1 new Object();public static Object Chopstick_2 new Object();public static void main(String[] args) {final DeadLock deadLock new DeadLock();// 第一個線程 new Thread(new Runnable() {public void run()…

python回歸分析實驗_python線性回歸實驗

實驗算法python線性回歸實驗【實驗名稱】Python線性回歸實驗【實驗要求】掌握Python線性回歸模型應用過程,根據模型要求進行數據預處理,建模,評價與應用;【背景描述】線性回歸是利用數理統計中回歸分析,來確定兩種或兩…