volatile底層詳解

2021-10-24 01:45:00 字數 1683 閱讀 5138

執行緒執行時把資料放到棧中:

1、啟動執行緒時,位元組碼執行引擎需要往棧裡面新增資料,而這些操作是需要通過cpu來完成的,

2、位元組碼執行引擎會把位元組碼交給解釋執行器或者jit優化(兩種方式)翻譯成彙編指令,彙編指令通過硬體翻譯成二進位制,也就是cpu能執行的二進位制語言;(位元組碼翻譯成彙編指令較慢,組合語言翻譯成二進位制是非常快的)但是cpu並不會馬上執行,因為cpu在執行執行緒的時候,會給每乙個執行緒分配一些時間片,只有等在他之前的時間片都執行完了,輪到執行這個執行緒的時間片時才會開始執行他的時間片;(執行緒是**的載體,只有執行緒被執行的時候才會被排程,我們的jvm是核心執行緒模型,在作業系統底層中會維護乙個執行緒表與我們jvm執行緒棧是一對一的關係)。

3、cpu排程執行緒,執行指令往棧中做乙個操作。

volatile可見性

lock(匯流排鎖)指令:當被volatile修飾時會加上lock(對變數加鎖操作)字首;

匯流排鎖:早期我們只使用匯流排鎖保證快取一致,早期沒有多級快取,可能就乙個快取,會被直接讀到cpu暫存器,當操作同乙個變數時就會因為同時操作互相覆蓋對方造成錯誤,加乙個匯流排鎖後,就不允許其他執行緒進入cpu。在匯流排處就將其他執行緒鎖住,只有發起鎖的那個執行緒擁有匯流排的使用權,其他執行緒不被允許使用匯流排,或者說在匯流排處無法進入cpu執行他的執行緒。弊端:多核cpu的情況下,其他cpu也不能訪問匯流排,也就是不能讀取記憶體,造成cpu空閒,效率低下;

快取一致性協議(mesi協議)

去代替匯流排做快取一致性保證可見性

1、當a變數被lock修飾後,cpu就會監聽a變數在匯流排中的變化,當被a變數第一次進入匯流排後,cpu會給這個變數標記成「獨享」狀態,如果一直處於獨享狀態肯定就沒什麼問題了。但是這個a(之後稱a2)變數在第乙個a(之後稱a1)變數還在cpu和快取行中存活時又進入了匯流排,那麼這兩個a變數就會被標記成共享狀態,這時當a1或者a2變數被操作修改後,就會通知匯流排,然後再由匯流排去通知另乙個還沒被修改的變數去匯流排中重新取值。這樣值就不會被重複修改,而是會重新取值,有了先後順序;當然也存在由a1和a2同時修改完畢,同時通知匯流排已經被修改了,那麼就會在匯流排做一次判斷,具體什麼判斷太底層不深究,最後得出乙個結果是a1或者a2其中乙個,而另乙個則重新取值。

2、當變數大小超過快取行大小(64位元組)時,快取行鎖就無法鎖住這麼大的物件,因為如果這個鎖是快取行級別的,如果物件是128位元組就需要兩次鎖才能鎖住這個物件,但是cpu執行是時間片執行的,我們不能保證執行完第乙個操作,馬上就會去執行第二個操作,當我們鎖住了物件的前半部分,而後半部分被其他後進來或者同時進來的物件鎖住的話,這就是bug了,所以當物件的大小超過乙個快取行的大小也就是超過64位元組的變數我們採用的是匯流排鎖來做快取一致性;

無法保證原子性

當我們需要做兩步操作時,volatile則無法保證原子性

比如當我們要執行乙個a=a+1;

1、首先我們肯定要給a賦值,假如這個值是0,先執行a=0操作;再執行a=0+1操作;

2、當a1和a2同時進入cpu進行a=a+1運算,而a1先a2一步完成了操作,並且去通知a2他已經完成操作了,那麼a2直接放棄執行+1操作,這就造成了a2=a2+1這步操作丟失了。明顯不合理;所以不能保證原子性;

有序性

**的有序性遵從先有底層建築後有上層建築的原則,被volatile修飾的就遵從volatile記憶體屏障的一些原則;

Volatile底層原理剖析

基礎知識回顧 還是那句話,無論語言再怎麼牛,其都是對底層計算機指令的封裝。計算機cpu執行指令的時候是非常快的,如果每執行乙個指令都從記憶體中取資料的話,那會非常慢,嚴重影響cpu的執行速度,所以每個cpu都有自身對應的高速緩衝區 多級暫存器 每個執行緒被執行的時候,會先把執行時需要的資料複製到告訴...

併發程式設計 volatile底層實現原理

解決可見性使用快取一致性。防止指令重排序使用記憶體屏障,保證有序性。有volatile變數修飾的共享變數,編譯時會有lock字首。lock字首指令會引起處理器快取回寫到記憶體。匯流排鎖 快取鎖 乙個處理器的快取回寫到記憶體會導致其他處理器的快取無效。mesi 嗅探 處理器上有一套完整的協議,來保證 ...

Mysql底層索引詳解

索引本質以及索引型別 mysql底層索引的資料結構是b tree b tree變種 非葉子節點不儲存data,只儲存索引,可以放更多的索引 順序訪問指標,提高區間訪問的效能。b tree樹節點的大小為16kb,每個樹的的結點會被load到記憶體,每次和磁碟進行一次io操作 比較耗時 乙個索引的記憶體...