java内存图解_图解JAVA内存模型(JMM:JAVA Memory Model)
本文主要說明兩個問題:JMM存在的意義是什么?JMM內(nèi)部的工作原理是什么(重點(diǎn)講一下并發(fā)編程模式下的數(shù)據(jù)訪問一致性問題) 。
1.為什么要使用JMM?
當(dāng)我們剛開始接觸JAVA語言的時候,就會被告知JAVA程序是可以實(shí)現(xiàn)跨平臺運(yùn)行的(即同一份代碼資源可運(yùn)行在不同的硬件配置下,不同的操作系統(tǒng)下)。那么JAVA 是如何在不同的硬件和操作系統(tǒng)內(nèi)存訪問方式存在差異的情況下,實(shí)現(xiàn) 同一個Java 程序在各種平臺下的運(yùn)行結(jié)果都相同(達(dá)到一致的內(nèi)存訪問效果)的呢。靠的就是神奇的JMM。
在這里要牢記兩個事實(shí):
(1)我們平時所寫的每一行程序代碼其實(shí)就是對計(jì)算機(jī)發(fā)出的一個操作指令,而這些指令的運(yùn)行空間是CPU。
(2)程序中不可避免的會涉及到對變量和臨時數(shù)據(jù)的讀取與寫入。而這些變量和臨時數(shù)據(jù)是存儲在物理內(nèi)存memory中的。
而CPU和內(nèi)存兩者之間存在一個很明顯的速度不匹配問題:
CPU 執(zhí)行速度很快,而從內(nèi)存讀取數(shù)據(jù)和向內(nèi)存寫入數(shù)據(jù)的過程跟 CPU 執(zhí)行指令的速度比起來要差幾個數(shù)量級,因此如果任何時候?qū)?shù)據(jù)的操作都要通過和內(nèi)存的交互來進(jìn)行,會大大降低指令執(zhí)行的速度。
為解決該矛盾,人們便在CPU和內(nèi)存之間增加了高速緩存cache,如下圖所示:
增加了cache后,程序的執(zhí)行過程就變?yōu)?#xff1a;
(1)將運(yùn)算需要的數(shù)據(jù)從主存復(fù)制一份到CPU的高速緩存當(dāng)中
(2)CPU進(jìn)行計(jì)算時就可以直接從它的高速緩存讀取數(shù)據(jù)和向其中寫入數(shù)據(jù)
(3)運(yùn)算結(jié)束之后,再將高速緩存中的數(shù)據(jù)刷新到主存當(dāng)中。
事實(shí)上,CPU上可能同時開多個線程,多個線程對同一份數(shù)據(jù)進(jìn)行訪問,很容易出現(xiàn)數(shù)據(jù)訪問不一致的問題。如何保證數(shù)據(jù)訪問的一致性是我們JMM要解決的關(guān)鍵問題。
2.JMM的內(nèi)部工作機(jī)制
java內(nèi)存模型和jvm內(nèi)存模型是不一樣,要區(qū)分開。如上圖所示,多個線程對共享變量并沒有直接采用加鎖的方式,其中
(1)實(shí)際內(nèi)存(也叫主內(nèi)存)中存儲的是待共享的變量值。
(2)CPU中每個線程可以保留共享變量的副本。其中保存共享副本的地方稱為每一個線程的工作內(nèi)存threadLocal。每一個線程只能直接操作對應(yīng)工作內(nèi)存中的變量。
而不同線程之間的變量值傳遞則需要通過主內(nèi)存(memory)來完成。如何保證主內(nèi)存和線程工作內(nèi)存的數(shù)據(jù)一致性,是我們需要重點(diǎn)關(guān)注的地方:
事實(shí)上,JMM中使用volatile關(guān)鍵字保證主內(nèi)存和線程工作內(nèi)存的數(shù)據(jù)一致性.
其工作原理大致如下:
(1)線程A的工作內(nèi)存中的變量一旦發(fā)生了變化,就會有監(jiān)視器檢測到該變化。
(2)檢測器通知CPU將該變化值刷新到內(nèi)存。
(3)其他線程B/C..,在使用同一個變量時,為保證訪問到的數(shù)據(jù)確實(shí)是線程A修改過的新數(shù)據(jù),其采用的是CAS樂觀鎖策略(簡單理解就是,永遠(yuǎn)以主存中的內(nèi)容為參考)。即,
1)拿自己工作內(nèi)存中的變量值和主存中的變量值比較
2)如果相等,則使用工作內(nèi)存threadLocal里的變量
3)如果不相等,則用主內(nèi)存的變量替換本地的變量
而JMM的性能問題,則是通過指令重排的方式保證。
總結(jié)
以上是生活随笔為你收集整理的java内存图解_图解JAVA内存模型(JMM:JAVA Memory Model)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java类型比较_Java数据类型的比较
- 下一篇: java上传文件到ftp_java实现文