作用
JMM(Java Memory Model)是java內(nèi)存模型。用來屏蔽不同硬件不同操作系統(tǒng)訪問內(nèi)存的差異性,確保java程序在不同平臺上能達(dá)到一致的內(nèi)存訪問效果。也就是同一個程序在不同的虛擬機(jī)上運(yùn)行,得到的結(jié)果是一致的。
規(guī)范
在jmm規(guī)范中,所有的變量(不包括局部變量和方法參數(shù))都存儲在主內(nèi)存中,每個線程都有自己的工作內(nèi)存,工作內(nèi)存中的變量是主內(nèi)存該變量的拷貝。
線程不能直接讀寫主內(nèi)存,只能操作自己工作內(nèi)存中的變量,然后再同步到主內(nèi)存,這樣其它線程就能看到本次修改。
主內(nèi)存是多個線程共享的,工作內(nèi)存是線程私有的。線程間的通信必須通過主內(nèi)存來完成
JMM三大特性
原子性:一個操作是不可分割,不可中斷的,一個線程在執(zhí)行時不會被其它線程干擾。java提供了synchronized關(guān)鍵字來保證原子性。
可見性:一個線程修改共享變量的值,其它線程能夠立即知道。java是通過volatile關(guān)鍵字來提供可見性,另外final和synchronized關(guān)鍵字也能實現(xiàn)可見性。
有序性:可以使用synchronized或者volatile關(guān)鍵字保證多線程之間操作的有序性。volatile是通過內(nèi)存屏障禁止指令重排序。synchronized代碼塊在多線程下是串行執(zhí)行。
JMM八種內(nèi)存操作
- lock(鎖定):作用于主內(nèi)存中的變量,把變量標(biāo)識為線程獨占的狀態(tài)。
- read(讀取):作用于主內(nèi)存的變量,把變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便下一步的load操作使用。
- load(加載):作用于工作內(nèi)存的變量,把read操作主存的變量放入到工作內(nèi)存的變量副本中。
- use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的變量傳輸?shù)綀?zhí)行引擎,每當(dāng)虛擬機(jī)遇到一個需要使用到變量的值的字節(jié)碼指令時將會執(zhí)行這個操作。
- assign(賦值):作用于工作內(nèi)存的變量,它把一個從執(zhí)行引擎中接受到的值賦值給工作內(nèi)存的變量副本中,每當(dāng)虛擬機(jī)遇到一個給變量賦值的字節(jié)碼指令時將會執(zhí)行這個操作。
- store(存儲):作用于工作內(nèi)存的變量,它把一個從工作內(nèi)存中一個變量的值傳送到主內(nèi)存中,以便后續(xù)的write使用。
- write(寫入):作用于主內(nèi)存中的變量,它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存的變量中。
-
unlock(解鎖):作用于主內(nèi)存的變量,它把一個處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定。
JMM八種內(nèi)存操作
happens-before原則
- 程序次序規(guī)則:在一個線程中,按照代碼的順序,前面的操作Happens-Before于后面的任意操作。
- volatile變量規(guī)則:對一個volatile變量的寫操作,Happens-Before于后續(xù)對這個變量的讀操作。
- 傳遞規(guī)則:如果A Happens-Before B,并且B Happens-Before C,則A Happens-Before C。
- 鎖定規(guī)則:對一個鎖的解鎖操作 Happens-Before于后續(xù)對這個鎖的加鎖操作。
- 線程啟動規(guī)則:如果線程A調(diào)用線程B的start()方法來啟動線程B,則start()操作Happens-Before于線程B中的任意操作。
- 線程終結(jié)規(guī)則:線程A等待線程B完成(在線程A中調(diào)用線程B的join()方法實現(xiàn)),當(dāng)線程B完成后(線程A調(diào)用線程B的join()方法返回),則線程A能夠訪問到線程B對共享變量的操作。
- 線程中斷規(guī)則:對線程interrupt()方法的調(diào)用Happens-Before于被中斷線程的代碼檢測到中斷事件的發(fā)生。
- 對象終結(jié)原則:一個對象的初始化完成Happens-Before于它的finalize()方法的開始。
