關於java鎖的知識體系
房間裡燈光昏暗,兩個男人相對而坐,
良久,眼睛男率先打破僵局,
眼睛男,知道鎖麼
帥氣男,知道些,
眼睛男:什麼是鎖?
一種保護機制,在多執行緒的情況下,保證操作資料的正確性/一致性,
眼鏡男:有哪幾種分類?
悲觀鎖,樂觀鎖,獨佔鎖,共享鎖,公平鎖,非公平鎖,分散式鎖,自旋鎖
眼睛男:講講樂觀鎖悲觀鎖吧
一般喜歡放在資料庫來講(其實這兩個概念是屬於計算機的,不要被誤導),就說mysql吧,悲觀鎖,主要是表鎖,行鎖還有間隙鎖,葉鎖,讀鎖,因為這些鎖在被觸發的時候勢必引起執行緒阻塞,所以叫悲觀, 另外樂觀鎖其實在mysql本身中不存在的,但是mysql提供了種mvcc的機制,支援樂觀鎖機制 ,
眼睛男:mvcc是咋回事?
只是在innodb引擎下存在,mvcc是為了滿足事務的隔離,通過版本號的方式,避免同一資料不同事務間的競爭,所說的樂觀鎖只在事務級別為讀未提交讀提交,才會生效,
眼睛男:具體mvcc機制有什麼?
多版本併發控制,保證資料操作在多執行緒過程中,保證事務隔離的機制,可以降低鎖競爭的壓力,保證比較高併發量,這個過程。在每開啟一個事務時,會生成一個事務的版本號,被操作的資料會生成一條新的資料行(臨時),但是在提交前對其他事務是不可見的,對於資料的更新操作成功,會將這個版本號更新到資料的行中,事務提交成功,將新的版本號,更新到此資料行(永久)中,這樣保證了每個事務操作的資料,都是相互不影響的,也不存在鎖的問題;
眼睛男:那麼在多個事務(操作同一條資料)併發過程中,誰先成功?
mysql判斷,其實就是誰先提交成功算誰的
眼睛男:說到事務了,聊聊事務,
事務常說一系列操作作為一個整體要麼都成功要麼都失敗,主要特性acid,事務的的實現主要依賴兩個log redo-log,undo-log,每次事務都會記錄資料修改前的資料undo-log,修改後的資料放入redo-log,提出成功則使用redo-log 更新到磁碟,失敗則使用undo-log將資料恢復到事務之前的資料
眼鏡男,嗯,再說說獨佔鎖,共享鎖吧
(嗯,獨佔,共享,公平,非公平,自旋鎖這些都是廣泛的概念,很多語言都有,包括作業系統,js的同學請回避)
獨佔鎖很明顯就是持鎖的執行緒只能有一個,共享鎖則可以有多個
眼睛男:獨佔可以理解,共享的意義在哪裡?
共享鎖是為了提高程式的效率,舉個例子資料的操作有讀寫之分,對於寫的操作加鎖,保證資料正確性,而對於讀的操作如果不加鎖,在寫讀操作同時進行時,讀的資料有可能不是最新資料,如果對讀操作加獨佔鎖,面對讀多寫少的程式肯定效率很低,所有就出現了共享鎖,對於讀的的操作就使用共享的概念,但是對於寫的操作則是互斥的,保證了讀寫的資料操作都一致,在java中上述的鎖叫讀寫鎖
眼睛男:讀寫鎖的機制是什麼呢?
在java中讀寫鎖(ReadWritelock)的機制是基於AQS的一種實現,保證讀讀共享,讀寫互斥,寫寫互斥,如果要說機制的話,還要從AQS說起,這是java實現的一種鎖機制,互斥鎖,讀者寫鎖,條件產量,訊號量,柵欄的都是它的衍生物,主要工作基於CHL佇列,voliate關鍵字修飾的狀態符stat,執行緒去修改狀態符成功了就是獲取成功,失敗了就進佇列等待,等待喚醒,AQS中還有很重要的一個概念是自旋,在等待喚醒的時候,很多時候會使用自旋(while(!cas()))的方式,不停的嘗試獲取鎖,直到被其他執行緒獲取成功
公平與非公平的區別就在於執行緒第一次獲取鎖時,也就是執行修改stat操作時,是進佇列還是直接修改狀態,這是基本的工作機制,詳細的估計可以再聊好幾集
眼睛男:java 除了AQS 還有其他的鎖支援麼
在java中,synchronized關鍵字,是語言自帶的,也叫內建鎖,synchronized關鍵字,我們都知道被synchronized修飾的方法或者程式碼塊,在同一時間內,只允許一個執行緒執行,是明顯的獨享鎖,synchronized的實現機制?可以參考AQS的實現方式,只是AQS使用顯示的用lock.lock()呼叫,而sync作為關鍵字修飾,你可以認為在synchronized修飾的地方,自動添加了lock方法,結束的地方進行了unlock釋放鎖的方法,只是被隱藏了,我們看不到。它本身實現有兩部分:monitor物件,執行緒,工作機制還是執行緒搶佔物件使用權,物件都有自己的物件頭,儲存了物件的很多資訊,其中有一個是標識被哪個執行緒持有,對比AQS,執行緒從修改stat,變為修改monitor的物件頭,執行緒的等待區域動 AQS中的佇列,變為monitor物件中的某個區域,
眼睛男:能細說麼?
鎖一直是圍繞執行緒安全來實現的,比如獨佔鎖,它在記憶體裡面的操作是怎麼樣的,這個地方涉及到一個概念,記憶體模型(這個和jvm不要混淆,The Java memory model used internally in the JVM divides memory between thread stacks and the heap. This diagram illustrates the Java memory model from a logic perspective),是JVM用來區別執行緒棧和堆的記憶體方式,每個執行緒在執行的時候,所操作的資料儲存空間有兩個,一個是主記憶體 一個是工作記憶體,主記憶體其實就是jvm中堆,工作記憶體就是執行緒的棧,每次的資料操作,都是從主記憶體中把資料讀到工作記憶體中,然後在工作記憶體中進行各種處理,如果進行了修改,會把資料回寫到主記憶體,然後其他執行緒又進行同樣的操作,就這樣資料在工作記憶體和主記憶體,進進出出,不亦樂乎,在多次的情況下,就是因為進進出出的順序亂了,不是按照執行緒預期的訪問順序,就出現了資料不一致的問題,導致了多執行緒的不安全性;整個操作過程還牽涉到CPU,快取記憶體等概念,略過。。。。
眼睛男:記憶體模型 還有哪些可以聊聊的(我們是抱著學習的心態)
happen-befor 原則,Volatile 關鍵字(執行緒的可見性),記憶體屏障
眼睛男:哦(慫了慫了)
happen-befor原則定義了記憶體模型執行過程中的定律,就像1+1 = 2,不可能被打破的jvm的執行機制都依賴於這個原則,是jvm的憲法!!!
Volatile關鍵字就有點叼了,Volatile修飾的資料,在被某個執行緒修改後,會被及時的回寫到主記憶體,然後其他執行緒再獲取時,就是新的資料,聽起來很美好,但是Volatile沒有辦法控制執行緒的順序,當一個數據(新資料)即將被修改到主記憶體時,剛好,另外一個執行緒從主記憶體讀了資料(老資料),並又進行了一波操作,又將資料(更新的資料)回寫到了主記憶體,整個過程(新資料)完全沒有起到一毛錢作用,最終導致了資料的錯誤,呼呼打完收工!!!!

眼鏡男:你為啥知道這麼多
因為我帥啊,
眼鏡男:有多帥?
可以用微笑殺死你
眼鏡男:來啊!
眼睛男猝 享年28歲!!!
。。。。。end。。。。。。
整個文章以“鎖”為半徑,構建了一個簡單的知識體系,直觀的感受一下

更詳細的請開啟 http://treenpool.com/html/index.html?branchId=488
本文旨在為大家擴寬思路,認識一下不太常見的概念,不要太糾結於細節!!!(慫了慫了),這是以點及面比較好的例子,從一個點不斷深入,你會發現很多新的東西,而這些就是需要一點一滴咀嚼的,看部落格或者視訊都是經過別人嚼爛消化過的東西,然後再吐出來展示給大家,大家看看他吃的啥就行,千萬不要再吃下去,因為真正的養分已經不多了,還是需要從書啃起,一口口嚼出來,經過味蕾,大腦,胃,大腸。。。。一點點吸收,才是自己的,這也是我個人平時學習的方法,也祝願大家可以用自己的方法,不斷提升自己,擴充套件自己的知識體系;本文很多描述的不是很完全,畢竟每個點隨隨便便就是幾千字的,本人能力有限,只能把最近吃的吐出來給大家看看,不知道是否符合大家的胃口,
最後!!!高能預警

歡迎大家加微信騷擾:treenpool
請持續關注, http://treenpool.com 致力於搭建個人知識體系的網站