內(nèi)存屏障

內(nèi)存屏障(Memory barrier)

為什么會有內(nèi)存屏障

  • 每個(gè)CPU都會有自己的緩存(有的甚至L1,L2,L3),緩存的目的就是為了提高性能,避免每次都要向內(nèi)存取。但是這樣的弊端也很明顯:不能實(shí)時(shí)的和內(nèi)存發(fā)生信息交換,分在不同CPU執(zhí)行的不同線程對同一個(gè)變量的緩存值不同。
  • 用volatile關(guān)鍵字修飾變量可以解決上述問題,那么volatile是如何做到這一點(diǎn)的呢?那就是內(nèi)存屏障,內(nèi)存屏障是硬件層的概念,不同的硬件平臺實(shí)現(xiàn)內(nèi)存屏障的手段并不是一樣,java通過屏蔽這些差異,統(tǒng)一由jvm來生成內(nèi)存屏障的指令。

內(nèi)存屏障是什么

  • 硬件層的內(nèi)存屏障分為兩種:Load BarrierStore Barrier即讀屏障和寫屏障。
  • 內(nèi)存屏障有兩個(gè)作用:
  1. 阻止屏障兩側(cè)的指令重排序;
  2. 強(qiáng)制把寫緩沖區(qū)/高速緩存中的臟數(shù)據(jù)等寫回主內(nèi)存,讓緩存中相應(yīng)的數(shù)據(jù)失效。
  • 對于Load Barrier來說,在指令前插入Load Barrier,可以讓高速緩存中的數(shù)據(jù)失效,強(qiáng)制從新從主內(nèi)存加載數(shù)據(jù);
  • 對于Store Barrier來說,在指令后插入Store Barrier,能讓寫入緩存中的最新數(shù)據(jù)更新寫入主內(nèi)存,讓其他線程可見。

java內(nèi)存屏障

  • java的內(nèi)存屏障通常所謂的四種即LoadLoad,StoreStore,LoadStore,StoreLoad實(shí)際上也是上述兩種的組合,完成一系列的屏障和數(shù)據(jù)同步功能。
  • LoadLoad屏障:對于這樣的語句Load1; LoadLoad; Load2,在Load2及后續(xù)讀取操作要讀取的數(shù)據(jù)被訪問前,保證Load1要讀取的數(shù)據(jù)被讀取完畢。
  • StoreStore屏障:對于這樣的語句Store1; StoreStore; Store2,在Store2及后續(xù)寫入操作執(zhí)行前,保證Store1的寫入操作對其它處理器可見。
  • LoadStore屏障:對于這樣的語句Load1; LoadStore; Store2,在Store2及后續(xù)寫入操作被刷出前,保證Load1要讀取的數(shù)據(jù)被讀取完畢。
  • StoreLoad屏障:對于這樣的語句Store1; StoreLoad; Load2,在Load2及后續(xù)所有讀取操作執(zhí)行前,保證Store1的寫入對所有處理器可見。它的開銷是四種屏障中最大的。在大多數(shù)處理器的實(shí)現(xiàn)中,這個(gè)屏障是個(gè)萬能屏障,兼具其它三種內(nèi)存屏障的功能

volatile語義中的內(nèi)存屏障

  • volatile的內(nèi)存屏障策略非常嚴(yán)格保守,非常悲觀且毫無安全感的心態(tài):

在每個(gè)volatile寫操作前插入StoreStore屏障,在寫操作后插入StoreLoad屏障;
在每個(gè)volatile讀操作前插入LoadLoad屏障,在讀操作后插入LoadStore屏障;

  • 由于內(nèi)存屏障的作用,避免了volatile變量和其它指令重排序、線程之間實(shí)現(xiàn)了通信,使得volatile表現(xiàn)出了鎖的特性。

final語義中的內(nèi)存屏障

  • 對于final域,編譯器和CPU會遵循兩個(gè)排序規(guī)則:
  1. 新建對象過程中,構(gòu)造體中對final域的初始化寫入和這個(gè)對象賦值給其他引用變量,這兩個(gè)操作不能重排序;(廢話嘛)
  2. 初次讀包含final域的對象引用和讀取這個(gè)final域,這兩個(gè)操作不能重排序;(晦澀,意思就是先賦值引用,再調(diào)用final值)
  • 總之上面規(guī)則的意思可以這樣理解,必需保證一個(gè)對象的所有final域被寫入完畢后才能引用和讀取。這也是內(nèi)存屏障的起的作用:
  • 寫final域:在編譯器寫final域完畢,構(gòu)造體結(jié)束之前,會插入一個(gè)StoreStore屏障,保證前面的對final寫入對其他線程/CPU可見,并阻止重排序。
  • 讀final域:在上述規(guī)則2中,兩步操作不能重排序的機(jī)理就是在讀final域前插入了LoadLoad屏障。
  • X86處理器中,由于CPU不會對寫-寫操作進(jìn)行重排序,所以StoreStore屏障會被省略;而X86也不會對邏輯上有先后依賴關(guān)系的操作進(jìn)行重排序,所以LoadLoad也會變省略。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容