java內(nèi)存模型的抽象結(jié)構(gòu)
實(shí)例域哮翘、靜態(tài)域渐溶、數(shù)組元素存儲在堆內(nèi)存,堆內(nèi)存是線程間共享的
局部變量颅和、方法定義參數(shù)傅事、異常處理參數(shù)不會在線程之間共享
java memory model
線程之間的共享內(nèi)存存儲在主內(nèi)存,每個(gè)線程都會有個(gè)本地的線程副本
重排序
- 編譯器優(yōu)化重排序
- 指令級并行重排序
- 內(nèi)存系統(tǒng)重排序
java內(nèi)存模型之happens-before
jmm的設(shè)計(jì)
jmm把happens-before要求禁止的重排序分為了兩類:
- 會改變程序執(zhí)行結(jié)果的重排序
- 不會改變程序執(zhí)行結(jié)果的重排序
jmm會這兩種不同性質(zhì)的重排序采用不同策略:
- 對于會改變程序執(zhí)行結(jié)果的重排序,jmm要求編譯器和處理器必須禁止這種重排序
- 對于不會改變程序執(zhí)行結(jié)果的重排序,jmm沒有要求(即為許可這種重排序)
happens-before的定義
- 如果一個(gè)操作happens-before另一個(gè)操作,那么第一個(gè)操作的執(zhí)行結(jié)果將對第二個(gè)操作可見峡扩,而且第一個(gè)操作的執(zhí)行順序排在第二個(gè)操作之前(從編程人員角度來說:如果A happens-before B,那么java內(nèi)存模型將向程序員保證-A操作的結(jié)果將對B可見,且A的執(zhí)行順序排在B之前.注意,這只是java內(nèi)存模型像程序員做出的保證)
- 兩個(gè)操作之間存在happens-before關(guān)系,并不意味這java平臺的具體實(shí)現(xiàn)必須按照happens-before關(guān)系指定的順序來執(zhí)行.如果重排序之后的執(zhí)行結(jié)果蹭越,與按happens-before關(guān)系執(zhí)行的結(jié)果一致,那么是運(yùn)行這種重排序(JMM其實(shí)是遵循一個(gè)基本原則:只要不改變程序的執(zhí)行結(jié)果{指的是單線程程序和正確同步的多線程程序},編譯器和處理器怎么優(yōu)化都行.JMM這么做的原因是:程序員對于這兩個(gè)操作是否真的被重排序并不關(guān)心,關(guān)心的是程序執(zhí)行時(shí)的語義不能被改變{既執(zhí)行結(jié)果不能被改變}.因此,happens-before關(guān)系本質(zhì)上和as-if-serial語義是一回事)。
happens-before規(guī)則
- 程序順序規(guī)則:一個(gè)線程中的每個(gè)操作,happens-before于該線程中的任意后續(xù)操作
- 監(jiān)視器鎖規(guī)則:對于一個(gè)鎖的解鎖,happens-before于隨后對這個(gè)鎖的加鎖
- volatile變量規(guī)則:對一個(gè)volatile域的寫,happens-before于任意后續(xù)對這個(gè)volatile域的讀
- 傳遞性:如果A happens-before B,且B happens-before C,那么A happens-before C教届。
- start()規(guī)則:如果線程A執(zhí)行操作ThreaB.start()(啟動線程B),那么A線程的 ThreaB.start()操作happens-before于線程B中的任意操作响鹃。
- join()規(guī)則:如果線程A執(zhí)行操作ThreaB.join()并成功返回,那么線程B中的任意操作happens-before于線程A從ThreaB.join()操作成功返回。