内存模型杂论
文章目錄
- 1. 對線程的非共享變量不做任何處理
- 2. 線程共享變量提供同步機制
- 1. 線程內的數據一致性保證
- 2. 同步方式
- 3. HAPPENS-BEFORE
??感覺最近看JAVA的內存模型相關的東西看的有點暈,加上之前看操作系統也接觸到操作系統層面也有內存模型的概念。在這里嘗試對內存模型做一個定義和解釋。這里有對內存模型的一個基本定義,不知道怎么翻譯才好,我覺得內存模型是一組規則,這一組規則定義了程序對內存中的單個或多個變量操作之間的可見性應該是怎么樣的。通過這些規則來規范對內存的讀寫操作,從而保證指令執行的正確性。
THE MEMORY MODEL DETERMINES WHAT VALUES CAN BE READ AT EVERY POINT IN THE PROGRAM內存模型存在的原因:
JAVA 內存模型的規則
1. 對線程的非共享變量不做任何處理
??對線程的非共享變量不做任何處理。也就是線程方法棧內的變量,這些變量不能被外部線程訪問到,所以不需要做太多同步性要求,這些變量由線程內的語義控制就行,也就是滿足線程內數據一致性AS-IF-SERIAL 這里有一些概念介紹。
2. 線程共享變量提供同步機制
1. 線程內的數據一致性保證
??對于共享變量,提供的有同步的機制,但是這些不是自動同步的,需要使用同步語義VOLATILE,SYNCHRONIZED去使用這些同步規則。 在沒有使用任何同步機制的情況下,JAVA內存模型只保證線程內的數據一致性(也稱為AS-IF-SERIAL),也就是在一個線程內,能夠保證對同一個變量的讀寫是保持嚴格的程序邏輯執行順序的,下面這個指令無法被重排序,因為第二條依賴了第一條。
INT A=5 INT B=A但是對于不同內存的操作,JMM是允許的,比如下面的這個,在執行的時候是可能改變的
THREAD 1 1: R2 = A; 2: B = 1; THREAD 1 2: B = 1; 1: R2 = A;這樣的調整是不影響JMM規范的,但是考慮下面這種情況,假如兩個線程并發的話,就會出現數據問題
THREAD 1 THREAD 2 1: R2 = A; 3: R1 = B; 2: B = 1; 4: A = 2;可能會出現R2 == 2 AND R1 == 1
所以對于共享變量的操作JMM提供了一些約束規范來進行保證共享數據的一致性
2. 同步方式
??JMM規定了一些同步操作,這些同步操作保證了程序在執行這些操作的順序性,對于一個線程來說,同步順序主要是規定了在單個線程內程序內的同步操作的順序必須按照書寫的順序執行(不會進行重排序),這些同步操作會保證禁止對應的指令重排序(指令重排序的概念主要還是對于單個線程來說的,對于多個線程來說,指令本來就是無序的),同時后面可以通過HAPPENS-BEFORE保證內存的可見性,對于多個同步操作來說,是這些操作之間具有先后的順序,也就是要滿足互斥性。
同步操作有
1.VOLATILE READ. A VOLATILE READ OF A VARIABLE. 2.VOLATILE WRITE. A VOLATILE WRITE OF A VARIABLE. 3.LOCK. LOCKING A MONITOR 4.UNLOCK. UNLOCKING A MONITOR. 5.THE (SYNTHETIC) FIRST AND LAST ACTION OF A THREAD. 6.ACTIONS THAT START A THREAD OR DETECT THAT A THREAD HAS TERMINATED (§17.4.4).對應的同步順序有
3. HAPPENS-BEFORE
HAPPENS-BEFORE 主要強調了可見性,
如果,A HAPPEN-BEFORE B, 那么A對共享內存所有的操作對B來說都是可見的
對應的HAPPEN-BEFORE有以下幾種
上面5條HAPPEN-BEFORE規則涵蓋了多線程編程中的鎖、共享變量讀寫、線程生命周期和對象初始化等等重要內容,普通開發人員不用深入了解JMM,只需要知道這5條規則,可以很輕松的處理多線程場景。
對于內存中的共享變量,JMM提供了HAPPEN-BEFORE規則來約束指令的重排序和緩存內存的可見性
好博客
HTTPS://MONKEYSAYHI.GITHUB.IO/2017/12/28/%E4%B8%80%E6%96%87%E8%A7%A3%E5%86%B3%E5%86%85%E5%AD%98%E5%B1%8F%E9%9A%9C/
VOLATILE 和 MESI的關系,是利用了不同的系統去實現VOLATILE,中間隔著好幾層
HTTPS://WWW.ZHIHU.COM/QUESTION/296949412
HTTPS://JUEJIN.IM/POST/5A2B53B7F265DA432A7B821C
JAVA JMM和操作系統的內存模型,他是根據不同的操作系統特性做了實現
HTTPS://WWW.ZHIHU.COM/QUESTION/296949412 第3條
VOLATILE 的JMM實現
當然VOLATILE還有一個作用是禁止了指令重排序,和內存屏障是不一樣的,指令重排序是指單個線程中,CPU執行的指令是按照順序執行的,內存屏障是指多個核同時運行的時候對主內存的讀寫的順序性或者說是可見性。
JMM使用上面四種屏障提供了JAVA程序運行時統一的內存模型,以VOLATILE為例:1)VOLATILE變量執行寫操作,會在寫之前插入STORESTORE BARRIERS,在寫之后插入STORELOAD BARRIERS。 解釋:VOLATILE變量在執行寫操作之前插入STORESTORE BARRIERS,代表在執行VOLATILE變量寫之前的所有STORE操作都已執行,數據同步到了內存中(將STORE BUFFER中的STORE操作刷新到內存);寫之后插入STORELOAD BARRIERS,代表該VOLATILE變量的寫操作也會立即刷新到內存中,其他線程會看到最新值。 2)VOLATILE變量執行讀操作,會在讀之前插入LOADLOAD BARRIERS,在讀之后插入LOADSTORE BARRIERS。 解釋:VOLATILE變量在執行讀操作之前插入LOADLOAD BARRIERS,代表在執行VOLATILE變量讀之前的所有LOAD從內存中獲取最新值;在讀之后插入LOADSTORE BARRIERS,代表該讀取VOLATILE變量獲得是內存中最新的值。內存模型的實現,操作系統內存模型實現
HTTPS://LJALPHABETA.GITBOOKS.IO/A-PRIMER-ON-MEMORY-CONSISTENCY-AND-CACHE-COHERENC/CONTENT/%E7%AC%AC%E4%B8%80%E7%AB%A0-CONSISTENCY.HTML
??指令重排序和PROGRAM ORDER 是不沖突的,PROGRAM ORDER 是指單線程而不是單核。注意,即使處理器完全按照程序順序(PROGRAM ORDER)執行指令也可能發生指令重排序哦(譯者注:比如第一個原因是前面的指令緩存MISS,而后面的指令緩存HIT。畢竟,緩存是透明的)。對于單線程程序來說,兩條對內存不同地址進行寫操作的指令發生了指令重排序,是不影響程序結果的。但是,在多線程情況下,比如表3.1, 如果對C1的兩條指令發生重排序,就會影響程序的最終結果。并且,寫指令重排序是不可預測的,你猜不準何時會發生。用緩存一致性協議時避免不了此問題的(緩
存是透明的)。
??內存模型和指令重排序是兩碼事兒,怎么來做區分呢,內存模型主要是為了解決應為緩存等問題導致了CPU執行的時候看到的數據不一致的問題
??指令重排序是指CPU對指令進行了重排,在時間順序上改變了執行的先后,而內存模型是假設CPU是執行的順序是正確的,如果保證在正確執行的順序下保證CPU看到的內存是一致的,所以單核CPU理論上是不需要內存屏障的,因為數據都是在一個CPU上面運算,所以一致性和可見性是沒有問題的。
參考這里,我覺得這里說的更有道理
HTTPS://MONKEYSAYHI.GITHUB.IO/2017/12/28/%E4%B8%80%E6%96%87%E8%A7%A3%E5%86%B3%E5%86%85%E5%AD%98%E5%B1%8F%E9%9A%9C/
內存屏障兼顧了對內存的可見性處理和指令的重排序約束
內存屏障的作用就是要保證CPU執行了對應的操作以后CPU看到的數據的一致性。
應該說的是內存屏障和指令重排序是兩個事兒,而不是說內存模型和指令重排序是兩個事兒,因為內存模型的支撐需要指令重排序的一些相關設置,同時內存模型也需要內存屏障的支撐,JAVA的內存屏障應該也是這個意思吧。
感覺JAVA的內存屏障也包括了對指令重排序的功能,同時包含了對緩存的管理功能。
我感覺指令重排序等是內存模型需要處理的問題之一,內存模型主要是為了處理多個線程的CPU看到的變量的值不一致的問題,我們允許這個不一致的情況有多嚴重,這就是內存模型,為了滿足內存模型,什么時候需要對指令重排序進行禁止,什么時候需要鎖緩存。這是兩個維度的事兒。
那種LOADSTORE的屏障不僅是禁止指令排序,同時需要滿足內存的可見性,要滿足內存的可見性,首先就不能讓指令重排序。
這個鏈接杰哥
HTTP://IFEVE.COM/COOKBOOK-RECIPES/
感覺內存屏障還是不包括指令重排,這個是JAVA規范的兩個方面,JVM實現這兩個方面保證使用的措施可能不同,但是某些情況下需要同時進行指令重排序的限制和指令重排序的限制
哪些可以作為常量
HTTPS://BLOG.CSDN.NET/U010798968/ARTICLE/DETAILS/72835255
volatile的一些問題
https://www.jianshu.com/p/6745203ae1fe
總結
- 上一篇: 自定义ik分词加载无效的问题分析
- 下一篇: free和top显示可用内存不一致