程序猿划水羣整理-關於併發鎖的機制等

程序猿划水羣整理

關於併發鎖的機制等

起因是個划水的人裝逼瞎問:能不能解釋一下樂觀鎖、悲觀鎖、偏向鎖、輕量級鎖、CAS是啥?

樂觀鎖、悲觀鎖

我的觀點:
在innodb的行表數據鎖定的時候好像有涉及到
悲觀是 先鎖定 禁止操作 ,樂觀是 先標記 二次操作判斷禁止操作 ?是這樣嗎

【肯定不是啊! 不過印象中確實是有類似的說法。。。。。】


金小水的說法:
悲觀鎖是指你拿了這個鎖,別人就要阻塞啥事幹不了
樂觀鎖是指你拿了這個鎖,別人知道他沒鎖,可以去幹別的事,等你用完鎖


這裏我覺得跟阻塞沒啥子關係 無所謂 ╮(╯_╰)╭ 之後大佬討論好像是沒啥關係

參考些文章看看:

https://blog.csdn.net/u013262534/article/details/81077745
https://blog.csdn.net/qq_32924343/article/details/80451875

在MySQL-InnoDB中確實有悲觀與樂觀鎖的說法:

Shared(樂觀鎖) and Exclusive Locks(互斥鎖):
        InnoDB有兩種鎖類型,Shared(s) and Exclusive(x) Locks(樂觀鎖和互斥鎖)。
        Shared(s)Locks:允許持有該鎖的事務讀取數據;
        Exclusive(x) Locks:允許持有鎖的事務插入,更新或修改數據;

這裏應該也叫共享鎖排他鎖。【具體可以看MySQL技術內幕-InnoDB存儲引擎第六章】

其他的說法:【跟我開始的說法有點像的】

悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型[數據庫]裏邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。


關於偏向鎖、輕量級鎖、CAS

金小水自解釋:CAS是一種藉助cpu指令保證原子操作的機制

這裏我贊同的是:馬大佬給的說法:

synchronized在jdk 1.6之前性能很差,因爲直接使用操作系統的同步機制,每次都要進行內核態用戶態轉換比較慢。

1.6的時候引入了偏向鎖和輕量級鎖偏向鎖是優化一個對象鎖一直只被一個線程持有的情況,也就是沒有多線程的情況,輕量級鎖優化的是多線程執行但是沒有競爭的情況,比如A持有鎖釋放鎖,然後B持有鎖釋放鎖。

jvm中所有對象都可以作爲鎖,鎖的信息保存在對象頭的mark word中,對象的鎖狀態通過3個bit表示,分別可能是:無鎖、偏向鎖、輕量級鎖、重量級鎖。jdk1.6以及之後,默認開啓偏向鎖,所以mark word默認初始化爲匿名偏向狀態,也就是狀態是偏向鎖,但是其mark word中的偏向線程ID爲0。

當一個線程進入synchronized代碼塊,需要持有鎖時,發現是匿名偏向狀態,會用CAS操作把線程ID從0改成當前線程ID,如果失敗,則說明發生競爭,膨脹爲輕量級鎖。

當這個線程再次持有這把鎖時,只要判斷是否偏向自己,如果偏向自己就直接成功,性能損耗非常低。**當另外一個線程要獲取鎖時,偏向鎖會膨脹爲輕量級鎖,**輕量級鎖是在線程棧上新建LockRecord,然後把mark word複製到LockRecord中,然後LockRecord的指針指向鎖對象,然後把mark word以CAS的方式替換爲LockRecord引用。如果CAS失敗,則膨脹爲重量級鎖。釋放鎖時先釋放線程棧中的LockRecord,然後在CAS的方式把mark word替換回去。

總結來說偏向鎖是一次CAS,後面簡單判斷,輕量級鎖是申請和釋放都CAS,所以性能都是比較好的。

參考文章:https://github.com/farmerjohngit/myblog/issues/14

我先去看看這個文章先。

看了2遍,還是一臉懵的。不是我這個水平的小白看的東的:

感覺上跟馬大佬的說法差不多,就是在java中是有多級鎖的轉換的,並且會根據徵用與CAS操作結果進行升級或解鎖。

而操作的CAS並不在,這一層進行實現的。

關於CAS的實現:【馬大佬】

【馬大佬】:
對應的系統調用
本質上都是依賴操作系統的能力
畢竟是直接使用操作系統的多線程機制
一個是jvm機制,一個java類庫

鎖機制是Java類庫的實現,而CAS是JVM機制與操作系統 來實現的。


關於monitor機制

金小水:我記得synchronize是藉助monitor機制
.........
馬大佬:那是重量級鎖纔有monitor對象
金小水:synchronize反編譯出來的字節碼就是帶monitor

參考文章:https://www.jianshu.com/p/7f8a873d479c

Java 提供的 monitor 機制,其實是 Object,synchronized 等元素合作形成的,甚至說外部的條件變量也是個組成部分。JVM 底層的 ObjectMonitor 只是用來輔助實現 monitor 機制的一種常用模式,但大多數文章把 ObjectMonitor 直接當成了 monitor 機制。

Java 對 monitor 的支持,是以機制的粒度提供給開發者使用的,也就是說,開發者要結合使用 synchronized 關鍵字,以及 Object 的 wait / notify 等元素,才能說自己利用 monitor 的機制去解決了一個生產者消費者的問題。

Java 語言中的 java.lang.Object 類,便是滿足這個要求的對象,任何一個 Java 對象都可以作爲 monitor 機制的 monitor object。

所以。。馬大佬的說法還是比較合理的。


關於 阻塞問題

我覺得周小魚的說法比較對:

周小魚:
我感覺cas只是快速失敗吧?
如果switch不成功,返回不就是false麼

cas原子操作,因爲不用考慮阻塞或者說鎖的問題,才比較快(?,cas本身應該沒有阻塞或者等待什麼東西的概念,這邊concurrenthashmap只有在cas返回true時纔會推出,
如果一直cas失敗
那這裏一樣是阻塞的

cas不保證操作成功就好
圖:說明併發不阻塞的情況
CAS圖解
false的時候外部重試就好
因爲本身沒用需要lock的東西,很快
估計是因爲鎖開銷遠大於 cas重試的次數

這個的說法,在上面的關於鎖與CAS的關係的討論上,就可以看出來的。

你可以用CAS實現阻塞,可以非阻塞 。 【出自馬大佬】


以上觀點都是大佬的,與本小白杭無關 ╮(╯_╰)╭

小杭整理 2020-03-09


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章