15.unsafe类的CAS是怎么保证原子性的?
老王:小陳啊,上一章我們講了usafe是個啥東西,以及unsafe提供的幾大類的功能
老王:這一章啊,我們要花個時間專門講unsafe提供的cas功能,這個cas的功能是我們后面將Atomic原子類體系的基礎。
小陳:cas功能?上一章的時候不是已經介紹過了嗎?
老王:上一章只是簡單的介紹了一下CAS功能而已,但是關于unsafe的cas功能底層是怎么保證原子性的?在操作系統層面是怎么實現的?這些東西我們還沒有講。
由于的后面的并發知識非常多的使用到了unsafe的cas功能,所以啊,我們今天專門花一章的時間,來把CAS底層的原理弄懂
小陳:哦哦,原來是這樣啊......
老王:上一章我們講解CAS操作的時候,是直接通過( 對象地址 + 對象內部屬性偏移量offset )直接定位到要修改的變量在內存的位置,然后在內存級別的比較數據和修改數據。也就是像下面的圖一樣:
操作的時候直接根據 o對象地址 + offset偏移量地址,定位到demo屬性在內存的位置,然后直接操作內存修改數據。
老王:由于CPU是不會直接讀寫主存的,數據讀取的時候還是先將數據讀取到高速緩存,然后通過高速緩存傳遞給CPU;寫數據的時候也是先高速緩存,然后再將高速緩存的數據寫入內存;于是可以得到下面的圖形:
老王:小陳啊,想想一下上面的那副圖,如果在多線程并發操作的時候會有什么問題?
小陳:多個線程或者多個CPU同時讀取和修改demo屬性的時候,可能會導致數據不一致的問題,比如我拿一個 i++ 的例子來說:
比如CPU0、CPU1都通過內存地址定位到 i 所在位置,然后同時讀取 i = 0,然后同時執行i++操作,再刷新會主內存,這個時候就會導致?i?的值不是我們想要的
老王:你說的沒錯,如果在多個CPU都可以同時操作一個共享變量的時候,就會出現你說的這個問題。
小陳:我記得CAS操作是可以保證原子性的,也就是同一個時間,同一個操作只允許一個CPU操作成功,它這個又是怎么保證的呢?
老王:這個啊,其實CAS底層的操作,還是會用到鎖的!!!,只不過這個鎖是比較輕量級的,不會導致線程沉睡,下面我來講講CAS加鎖來保證原子性的原理。
CAS底層使用鎖保證原子性
老王:說起CAS操作啊,我還是畫圖給你比較好講一點:
(1)首先CPU0要執行CAS操作對變量 i 進行賦值,然后CPU0告訴總線說我要申請單獨操作變量 i 的權限,幫我告訴一下CPU1等其它的CPU兄弟
(2)總線通知到了CPU1,CPU1告訴總線,好的,我不會操作數據,讓CPU0大膽的去操作吧
(3)然后總線告訴CPU0,你可以獨占變量 i?的操作了,其它的兄弟表示不會干擾你
(4)然后CPU0從自己的緩存讀取 變量 i 的值;然后又根據 (o對象地址 + offset偏移量地址) 直接定位到變量 i 在內存的位置,直接讀取變量 i 在內存的值
(5)接下來的操作就簡單了,由于不會有人干擾,直接對比緩存的值和內存的值是否一致就可以了,如果一致,我直接修改,然后刷回主內存;如果不一致,說明我本地的數據不是最新的,需要重新申請CAS操作。
老王:小陳啊,這個就是CAS在底層操作的原理,它底層還是通過加鎖來保證原子性的,同一個時間只能有一個CPU能申請到CAS的操作權限,你理解了嗎?
小陳:哈哈,老王,你畫的這個圖太好了,我看到圖就知道它是怎么操作的了,真牛啊......
老王:好的,那這一張CAS底層加鎖保證原子性的討論我們就到這里了,我們明天繼續...
小陳:好的,老王......
老王:我們從下一章開始,就開始進入JUC提供的Atomic原子類的學習了......
小陳:那我們下一章見。
關注小陳,公眾號上更多更全的文章
JAVA并發文章目錄(公眾號)
JAVA并發專題 《筑基篇》
1.什么是CPU多級緩存模型?
2.什么是JAVA內存模型?
3.線程安全之可見性、有序性、原子性是什么?
4.什么是MESI緩存一致性協議?怎么解決并發的可見性問題?
JAVA并發專題《練氣篇》
5.volatile怎么保證可見性?
6.什么是內存屏障?具有什么作用?
7.volatile怎么通過內存屏障保證可見性和有序性?
8.volatile為啥不能保證原子性?
9.synchronized是個啥東西?應該怎么使用?
10.synchronized底層之monitor、對象頭、Mark Word?
11.synchronized底層是怎么通過monitor進行加鎖的?
12.synchronized的鎖重入、鎖消除、鎖升級原理?無鎖、偏向鎖、輕量級鎖、自旋、重量級鎖
13.synchronized怎么保證可見性、有序性、原子性?
JAVA并發專題《結丹篇》
14. JDK底層Unsafe類是個啥東西?
15.unsafe類的CAS是怎么保證原子性的?
16.Atomic原子類體系講解
17.AtomicInteger、AtomicBoolean的底層原理
18.AtomicReference、AtomicStampReference底層原理
19.Atomic中的LongAdder底層原理之分段鎖機制
20.Atmoic系列Strimped64分段鎖底層實現源碼剖析
JAVA并發專題《金丹篇》
21.AQS是個啥?為啥說它是JAVA并發工具基礎框架?
22.基于AQS的互斥鎖底層源碼深度剖析
23.基于AQS的共享鎖底層源碼深度剖析
24.ReentrantLock是怎么基于AQS實現獨占鎖的?
25.ReentrantLock的Condition機制底層源碼剖析
26.CountDownLatch 門栓底層源碼和實現機制深度剖析
27.CyclicBarrier 柵欄底層源碼和實現機制深度剖析
28.Semaphore 信號量底層源碼和實現機深度剖析
29.ReentrantReadWriteLock 讀寫鎖怎么表示?
30. ReentrantReadWriteLock 讀寫鎖底層源碼和機制深度剖析
JAVA并發專題《元神篇》并發數據結構篇
31.CopyOnAarrayList 底層分析,怎么通過寫時復制副本,提升并發性能?
32.ConcurrentLinkedQueue 底層分析,CAS 無鎖化操作提升并發性能?
33.ConcurrentHashMap詳解,底層怎么通過分段鎖提升并發性能?
34.LinkedBlockedQueue 阻塞隊列怎么通過ReentrantLock和Condition實現?
35.ArrayBlockedQueued 阻塞隊列實現思路竟然和LinkedBlockedQueue一樣?
36.DelayQueue 底層源碼剖析,延時隊列怎么實現?
37.SynchronousQueue底層原理解析
JAVA并發專題《飛升篇》線程池底層深度剖析
38. 什么是線程池?看看JDK提供了哪些默認的線程池?底層竟然都是基于ThreadPoolExecutor的?
39.ThreadPoolExecutor 構造函數有哪些參數?這些參數分別表示什么意思?
40.內部有哪些變量,怎么表示線程池狀態和線程數,看看道格.李大神是怎么設計的?
41. ThreadPoolExecutor execute執行流程?怎么進行任務提交的?addWorker方法干了啥?什么是workder?
42. ThreadPoolExecutor execute執行流程?何時將任務提交到阻塞隊列? 阻塞隊列滿會發生什么?
43. ThreadPoolExecutor 中的Worker是如何執行提交到線程池的任務的?多余Worker怎么在超出空閑時間后被干掉的?
44. ThreadPoolExecutor shutdown、shutdownNow內部核心流程
45. 再回頭看看為啥不推薦Executors提供幾種線程池?
46. ThreadPoolExecutor線程池篇總結
總結
以上是生活随笔為你收集整理的15.unsafe类的CAS是怎么保证原子性的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看 Amazon 如何通过 Nitro
- 下一篇: 【R语言】批量合并Excel文件,并增加