本篇內(nèi)容介紹了“Java內(nèi)存模型的規(guī)定是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
專業(yè)成都網(wǎng)站建設(shè)公司,做排名好的好網(wǎng)站,排在同行前面,為您帶來客戶和效益!創(chuàng)新互聯(lián)公司為您提供成都網(wǎng)站建設(shè),五站合一網(wǎng)站設(shè)計制作,服務(wù)好的網(wǎng)站設(shè)計公司,成都網(wǎng)站建設(shè)、成都做網(wǎng)站負(fù)責(zé)任的成都網(wǎng)站制作公司!首先要明確內(nèi)存模型指什么。書中的定義是:在特定的操作協(xié)議下,對特定內(nèi)存和高速緩存進(jìn)行讀寫訪問的過程抽象。 |
可以知道,內(nèi)存模型就是來規(guī)定如何對內(nèi)存/緩存進(jìn)行讀寫操作的。所以Java內(nèi)存模型,就是用來定義程序?qū)ava內(nèi)存的的訪問規(guī)則。進(jìn)一步說, Java內(nèi)存模型就是定義程序中變量(靜態(tài)變量、數(shù)組對象元素等,不包括局部變量、方法參數(shù))的訪問規(guī)則。
Java內(nèi)存模型的規(guī)定:
所有變量存儲在主內(nèi)存中;
每個線程都有自己的工作內(nèi)存,且對變量的操作都是在工作內(nèi)存中進(jìn)行;
不同線程之間無法直接訪問彼此工作內(nèi)存中的變量,要想訪問只能通過主內(nèi)存來傳遞。
Java的線程、工作內(nèi)存、主內(nèi)存關(guān)系如下圖所示:
具體變量從主內(nèi)存到工作內(nèi)存,以及從工作內(nèi)存轉(zhuǎn)回主內(nèi)存的實現(xiàn)細(xì)節(jié),由下面八個原子性的操作完成:
lock:作用于主內(nèi)存變量,將該變量標(biāo)識為一個線程獨占的狀態(tài)
unlock:作用于主內(nèi)存變量,將獨占狀態(tài)釋放
read:作用于主內(nèi)存變量,將值拷貝到工作內(nèi)存中
load:作用于工作內(nèi)存中的變量,將值放到工作內(nèi)存中的變量副本中
use:作用于工作內(nèi)存中的變量,將值傳給執(zhí)行引擎
asign:作用于工作內(nèi)存中的變量,將執(zhí)行引擎中的值賦給工作內(nèi)存中的變量
store:作用于工作內(nèi)存中的變量,將值傳給主內(nèi)存
write:作用于主內(nèi)存中的變量,將工作內(nèi)存中返回的值放到主內(nèi)存變量中
同時還對上述八個操作進(jìn)行了一些細(xì)節(jié)的要求,比如read/load、store/write必須成對出現(xiàn),未執(zhí)行過lock的變量不能執(zhí)行unlock操作等。
劃重點,此處面試常遇到的問題就是對于volatile關(guān)鍵字的解讀。
volatile關(guān)鍵字
此關(guān)鍵字修飾的變量具有兩種效果:1、保證線程間的可見性;2、阻止指令重排序
對于1的實現(xiàn),它保證load與use必須相鄰調(diào)用,即要use這個變量,必定先執(zhí)行read/load,這樣每次都能獲取到最新的變量值;它又保證asign與store必須相鄰調(diào)用,即在工作內(nèi)存中將該變量改了之后,必定會先同步到主內(nèi)存中。這樣,volatile關(guān)鍵字實現(xiàn)了可見性。至于阻止指令重排序,還是移步《深入理解Java虛擬機》一書吧,貧道水平有限,就不在這里說了。
從另一個角度來分析,Java內(nèi)存模型是圍繞著在并發(fā)過程中如何處理原子性、可見性、有序性來建立的。
原子性:八個原子性操作,以及synchronized(lock/unlock未直接開放給用戶,synchronized通過monitorenter跟monitorexit指令調(diào)用的lock/unlock操作)
可見性:volatile、synchronized、final這三個關(guān)鍵字均通過不同方式實現(xiàn)了可見性
有序性:volatile、synchronized 這兩個關(guān)鍵字保證有序性,同時還有先行發(fā)生(happens-before)原則來保證隱含的默認(rèn)有序性
下面說說happens-before先行發(fā)生原則,先行發(fā)生原則用通俗語言表述就是:如果操作A在操作B之前發(fā)生,那么A產(chǎn)生的影響B(tài)同樣能觀測到。那么問題來了,先行發(fā)生原則都有哪些呢?同樣有八條,如下:
程序次序規(guī)則:同一個線程中按照代碼的順序依次執(zhí)行
管程鎖定規(guī)則:對于同一個鎖,unlock先行發(fā)生于后面的lock,即unlock了才會lock
volatile變量規(guī)則:對一個volatile變量的寫操作先行發(fā)生于后面對該變量的讀操作,即寫完了才會讀
線程啟動規(guī)則:一個線程的start()方法先行發(fā)生于此線程的任何一個動作
線程終止規(guī)則:一個線程的所有動作先行發(fā)生于該線程的終止檢測
線程中斷規(guī)則:對一個線程interrupt()方法的調(diào)用先行發(fā)生于線程的中斷檢測Thread.interrpted()
對象終結(jié)規(guī)則:對象的初始化完成先行發(fā)生于finalize()方法
傳遞性:顧名思義,A先行發(fā)生于B,B先行發(fā)生于C,則A一定先行發(fā)生于C
“Java內(nèi)存模型的規(guī)定是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!