【狂神说】JVM
文章目錄
- 1.JVM的位置
- 2.JVM的體系結(jié)構(gòu)
- 3.類加載器
- 4.雙親委派機(jī)制(重要)
- 5.沙箱安全機(jī)制(了解)
- 6.native(核心)
- 7.PC寄存器(了解)
- 8.方法區(qū)
- 9.棧
- 10.三種JVM
- 11.堆(Heap)
- 12.新生區(qū)、老年區(qū)
- 13.永久區(qū)
- 14.堆內(nèi)存調(diào)優(yōu)
- 15.GC以及常用算法
- 引用計(jì)數(shù)法:
- 復(fù)制算法:
- 標(biāo)記清除算法:
- 標(biāo)記壓縮算法:
- 16.JMM
- 1、什么是JMM?
- 2、它干嘛的?
- 3、它該如何學(xué)習(xí)?
- 17.總結(jié)
常見的面試題:
- 請(qǐng)談一談你對(duì)JVM的理解?Java8虛擬機(jī)和之前的變化?
- 什么是OOM,什么是棧溢出?
- JVM的常用調(diào)優(yōu)參數(shù)有哪些
- 內(nèi)存快照如何抓取,怎么分析Dump文件?
- 談?wù)凧VM中你認(rèn)識(shí)的類加載器
1.JVM的位置
類加載子系統(tǒng):加載、鏈接、初始化
第三方插件:執(zhí)行引擎處
Class File–javac
2.JVM的體系結(jié)構(gòu)
Java棧、本地方法棧、程序計(jì)數(shù)器不會(huì)有垃圾回收,否則程序會(huì)死掉
百分之99的JVM調(diào)優(yōu)都是在方法區(qū)和堆(99%是堆)中調(diào)優(yōu),Java棧、本地方法棧、程序計(jì)數(shù)器是不會(huì)有垃圾存在的。
3.類加載器
作用:加載class文件 new Student();
(有一個(gè)student的類,這個(gè)類是抽象的,當(dāng)使用new關(guān)鍵詞new完后變成具體的實(shí)例,具體的實(shí)例在Java在棧中引用,具體的人實(shí)例放在堆中,要去堆中進(jìn)行真正的數(shù)據(jù)引用)
類是模板,是抽象的,類實(shí)例化得到的對(duì)象是具體的。所有的對(duì)象反射回去得到的是同一個(gè)類模板。
4.雙親委派機(jī)制(重要)
工作原理:
(1)如果一個(gè)類加載器收到了類加載請(qǐng)求,它并不會(huì)自己先加載,而是把這個(gè)請(qǐng)求委托給父類的加載器去執(zhí)行
(2)如果父類加載器還存在其父類加載器,則進(jìn)一步向上委托,依次遞歸,請(qǐng)求最終將到達(dá)頂層的引導(dǎo)類加載器;
(3)如果父類加載器可以完成類加載任務(wù),就成功返回,倘若父類加載器無(wú)法完成加載任務(wù),子加載器才會(huì)嘗試自己去加載,這就是雙親委派機(jī)制
(4)父類加載器一層一層往下分配任務(wù),如果子類加載器能加載,則加載此類,如果將加載任務(wù)分配至系統(tǒng)類加載器也無(wú)法加載此類,則拋出異常
當(dāng)一個(gè)Hello.class這樣的文件要被加載時(shí)。不考慮我們自定義類加載器,
首先會(huì)在AppClassLoader中檢查是否加載過,如果有那就無(wú)需再加載了。
如果沒有,那么會(huì)拿到父加載器,然后調(diào)用父加載器的loadClass方法。
父類中同理也會(huì)先檢查自己是否已經(jīng)加載過,如果沒有再往上。
注意這個(gè)類似遞歸的過程,直到到達(dá)Bootstrap classLoader之前,都是在檢查是否加載過,并不會(huì)選擇自己去加載。直到BootstrapClassLoader,已經(jīng)沒有父加載器了,這時(shí)候開始考慮自己是否能加載了,如果自己無(wú)法加載,會(huì)下沉到子加載器去加載,一直到最底層,如果沒有任何加載器能加載,就會(huì)拋出ClassNotFoundException。那么有人就有下面這種疑問了?
為什么要設(shè)計(jì)這種機(jī)制?
這種設(shè)計(jì)有個(gè)好處是,如果有人想替換系統(tǒng)級(jí)別的類:String.java。篡改它的實(shí)現(xiàn),在這種機(jī)制下這些系統(tǒng)的類已經(jīng)被Bootstrap classLoader加載過了(為什么?因?yàn)楫?dāng)一個(gè)類需要加載的時(shí)候,最先去嘗試加載的就是BootstrapClassLoader),所以其他類加載器并沒有機(jī)會(huì)再去加載,從一定程度上防止了危險(xiǎn)代碼的植入。
舉例一、
我自己建立一個(gè) java.lang.String 類,寫上 static 代碼塊
package java.lang;public class String {static{System.out.println("我是自定義的String類的靜態(tài)代碼塊");} }在另外的程序中加載 String 類,看看加載的 String 類是 JDK 自帶的 String 類,還是我們自己編寫的 String 類
public class StringTest {public static void main(String[] args) {java.lang.String str = new java.lang.String();System.out.println("hello,atguigu.com");StringTest test = new StringTest();System.out.println(test.getClass().getClassLoader());} }為什么呢?
由于我們定義的String類本應(yīng)用系統(tǒng)類加載器,但它并不會(huì)自己先加載,而是把這個(gè)請(qǐng)求委托給父類的加載器去執(zhí)行,到了擴(kuò)展類加載器發(fā)現(xiàn)String類不歸自己管,再委托給父類加載器(引導(dǎo)類加載器),這時(shí)發(fā)現(xiàn)是java.lang包,這事就歸引導(dǎo)類加載器管,所以加載的是 JDK 自帶的 String 類
舉例二、
在我們自己的 String 類中整個(gè) main() 方法
package java.lang;public class String {static{System.out.println("我是自定義的String類的靜態(tài)代碼塊");}//錯(cuò)誤: 在類 java.lang.String 中找不到 main 方法public static void main(String[] args) {System.out.println("hello,String");} }由于雙親委派機(jī)制找到的是 JDK 自帶的 String 類,但在引導(dǎo)類加載器的核心類庫(kù)API里的 String 類中并沒有 main() 方法
舉例三、
舉例 3:
在 java.lang 包下整個(gè) ShkStart 類 (自定義類名)
出于保護(hù)機(jī)制,java.lang 包下不允許我們自定義類
雙親委派機(jī)制優(yōu)勢(shì)
通過上面的例子,我們可以知道,雙親機(jī)制可以
- 避免類的重復(fù)加載
- 保護(hù)程序安全,防止核心API被隨意篡改
- 自定義類:java.lang.String (沒用)
- 自定義類:java.lang.ShkStart(報(bào)錯(cuò):阻止創(chuàng)建 java.lang開頭的類)
5.沙箱安全機(jī)制(了解)
Java安全模型的核心就是Java沙箱(sanddiox),什么是沙箱?沙箱是一個(gè)限制程序運(yùn)行的環(huán)境。沙箱機(jī)制就是將Java代碼限定在虛擬機(jī) (JVM) 特定的運(yùn)行范圍中,并且嚴(yán)格限制代碼對(duì)本地系統(tǒng)資源訪問,通過這樣的措施來(lái)保證對(duì)代碼的有效隔離,防止對(duì)本地系統(tǒng)造成破壞。沙箱主要限制系統(tǒng)資源訪問,那系統(tǒng)資源包括什么? CPU、內(nèi)存、文件系統(tǒng)、網(wǎng)絡(luò)。不同級(jí)別的沙箱對(duì)這些資源訪問的限制也可以不一樣。
所有的Java程序運(yùn)行都可以指定沙箱,可以定制安全策略。
在Java中將執(zhí)行程序分成本地代碼和遠(yuǎn)程代碼兩種,本地代碼默認(rèn)視為可信任的,而遠(yuǎn)程代碼則被看作是不受信的。對(duì)于授信的本地代碼,可以訪問一切本地資源。而對(duì)于非授信的遠(yuǎn)程代碼在早期的Java實(shí)現(xiàn)中,安全依賴于沙箱(Sandbox)機(jī)制。如下圖所示JDK1.0安全模型
但如此嚴(yán)格的安全機(jī)制也給程序的功能擴(kuò)展帶來(lái)障礙,比如當(dāng)用戶希望遠(yuǎn)程代碼訪問本地系統(tǒng)的文件時(shí)候,就無(wú)法實(shí)現(xiàn)。因此在后續(xù)的Java1.1版本中,針對(duì)安全機(jī)制做了改進(jìn),增加了安全策略,允許用戶指定代碼對(duì)本地資源的訪問權(quán)限。如下圖所示JDK1.1安全模型
在Java1.2版本中,再次改進(jìn)了安全機(jī)制,增加了代碼簽名。不論本地代碼或是遠(yuǎn)程代碼,都會(huì)按照用戶的安全策略設(shè)定,由類加載器加載到虛擬機(jī)中權(quán)限不同的運(yùn)行空間,來(lái)實(shí)現(xiàn)差異化的代碼執(zhí)行權(quán)限控制。如下圖所示
當(dāng)前最新的安全機(jī)制實(shí)現(xiàn),則引入了**域(Domain)**的概念。虛擬機(jī)會(huì)把所有代碼加載到不同的系統(tǒng)域和應(yīng)用域,系統(tǒng)域部分專門負(fù)責(zé)與關(guān)鍵資源進(jìn)行交互,而各個(gè)應(yīng)用域部分則通過系統(tǒng)域的部分代理來(lái)對(duì)各種需要的資源進(jìn)行訪問。虛擬機(jī)中不同的受保護(hù)域(Protected Domain),對(duì)應(yīng)不一樣的權(quán)限(Permission)。存在于不同域中的類文件就具有了當(dāng)前域的全部權(quán)限,如下圖所示最新的安全模型(jdk 1.6)
組成沙箱的基本組件
字節(jié)碼校驗(yàn)器(bytecode verifier):確保Java類文件遵循Java語(yǔ)言規(guī)范。這樣可以幫助Java程序?qū)崿F(xiàn)內(nèi)存保護(hù)。但并不是所有的類文件都會(huì)經(jīng)過字節(jié)碼校驗(yàn),比如核心類。
類裝載器(class loader) :其中類裝載器在3個(gè)方面對(duì)Java沙箱起作用
它防止惡意代碼去干涉善意的代碼; //雙親委派機(jī)制
它守護(hù)了被信任的類庫(kù)邊界;
它將代碼歸入保護(hù)域,確定了代碼可以進(jìn)行哪些操作。
虛擬機(jī)為不同的類加載器載入的類提供不同的命名空間,命名空間由一系列唯一的名稱組成, 每一個(gè)被裝載的類將有一個(gè)名字,這個(gè)命名空間是由Java虛擬機(jī)為每一個(gè)類裝載器維護(hù)的,它們互相之間甚至不可見。 ?
類裝載器采用的機(jī)制是雙親委派模式。
從最內(nèi)層JVM自帶類加載器開始加載,外層惡意同名類得不到加載從而無(wú)法使用;
由于嚴(yán)格通過包來(lái)區(qū)分了訪問域,外層惡意的類通過內(nèi)置代碼也無(wú)法獲得權(quán)限訪問到內(nèi)層類,破壞代碼就自然無(wú)法生效。
●存取控制器(access controller) :存取控制器可以控制核心API對(duì)操作系統(tǒng)的存取權(quán)限,而這個(gè)控制的策略設(shè)定,可以由用戶指定。
●安全管理器(security manager) : 是核心API和操作系統(tǒng)之間的主要接口。實(shí)現(xiàn)權(quán)限控制,比存取控制器優(yōu)先級(jí)高。
●安全軟件包(security package) : java.security下的類和擴(kuò)展包下的類,允許用戶為自己的應(yīng)用增加新的安全特性,包括:
安全提供者
消息摘要
數(shù)字簽名 keytools https
加密
鑒別
6.native(核心)
native:
凡是帶了native關(guān)鍵字的,說明java的作用范圍達(dá)不到了,會(huì)去調(diào)用底層c語(yǔ)言的庫(kù)
會(huì)進(jìn)入本地方法棧
調(diào)用本地方法本地接口 JNI (Java Native Interface)
JNI作用:開拓Java的使用,融合不同的編程語(yǔ)言為Java所用,最初: C、C++
Java誕生的時(shí)候C、C++橫行,想要立足,必須要有調(diào)用C、C++的程序
它在內(nèi)存區(qū)域中專門開辟了一塊標(biāo)記區(qū)域: Native Method Stack,登記native方法
在最終執(zhí)行的時(shí)候,加載本地方法庫(kù)中的方法通過JNI
例如:Java程序驅(qū)動(dòng)打印機(jī),管理系統(tǒng),掌握即可,在企業(yè)級(jí)應(yīng)用比較少
private native void start0();
調(diào)用其他接口:Socket… WebService … http~
? 目前該方法使用的越來(lái)越少了,除非是與硬件有關(guān)的應(yīng)用,比如通過Java程序驅(qū)動(dòng)打印機(jī)或者Java系統(tǒng)管理設(shè)備,在企業(yè)級(jí)應(yīng)用中已經(jīng)比較少見。因?yàn)楝F(xiàn)在的異構(gòu)領(lǐng)域間通信很發(fā)達(dá),比如可以使用Socket通信,也可以使用Web Service等等,不多做介紹!
Native Method Stack
它的具體做法是Native Method Stack 中登記native方法,在 ( Execution Engine ) 執(zhí)行引擎執(zhí)行的時(shí)候加載Native Libraies?!颈镜貛?kù)】
7.PC寄存器(了解)
程序計(jì)數(shù)器: Program Counter Register ?
?每個(gè)線程都有一個(gè)程序計(jì)數(shù)器,是線程私有的,就是一個(gè)指針, 指向方法區(qū)中的方法字節(jié)碼(用來(lái)存儲(chǔ)指向像一條指令的地址, 也即將要執(zhí)行的指令代碼),在執(zhí)行引擎讀取下一條指令, 是一個(gè)非常小的內(nèi)存空間,幾乎可以忽略不計(jì)
8.方法區(qū)
方法區(qū):Method Area
? 方法區(qū)是被所有線程共享,所有字段和方法字節(jié)碼,以及一些特殊方法,如構(gòu)造函數(shù),接口代碼也在此定義,簡(jiǎn)單說,所有定義的方法的信息都保存在該區(qū)域,此區(qū)域?qū)儆诠蚕韰^(qū)間;
靜態(tài)變量、常量、類信息(構(gòu)造方法、接口定義)、運(yùn)行時(shí)的常量池存在方法區(qū)中,但是實(shí)例變量存在堆內(nèi)存中,和方法區(qū)無(wú)關(guān)
static、final、Class、常量池
9.棧
1、棧:數(shù)據(jù)結(jié)構(gòu)(棧跟隊(duì)列比較學(xué)習(xí))
程序 = 數(shù)據(jù)結(jié)構(gòu)+算法︰持續(xù)學(xué)習(xí)~
程序 = 框架+業(yè)務(wù)邏輯︰吃飯~(被淘汰)(springboot+springcloud)
棧:先進(jìn)后出、后進(jìn)先出,類似一個(gè)桶()
隊(duì)列:先進(jìn)先出( FIFO : First Input First Output )
為什么main()先執(zhí)行,最后結(jié)束~(main()方法先壓入棧,再壓入其他方法,main()最后彈出)
棧溢出:StackOverflowError
public void test(){a(); } public void a(){test(); }棧:也叫棧內(nèi)存
主管程序的運(yùn)行,生命周期和線程同步;
線程結(jié)束,棧內(nèi)存也就釋放,對(duì)于棧來(lái)說,==不存在垃圾回收的問題;==一旦線程結(jié)束,棧就Over;
棧:棧內(nèi)存中放8大基本類型+對(duì)象引用+實(shí)例的方法
棧運(yùn)行原理:棧幀
棧幀:局部變量表+操作數(shù)棧
每執(zhí)行一個(gè)方法,就會(huì)產(chǎn)生一個(gè)棧幀。程序正在運(yùn)行的方法永遠(yuǎn)都會(huì)在棧的頂部
棧+堆+方法區(qū)的交互關(guān)系:
查的內(nèi)容:棧具體怎么存
手動(dòng)畫出一個(gè)對(duì)象實(shí)例化的過程在內(nèi)存中(百度、視頻)
調(diào)優(yōu)是在堆中調(diào)優(yōu),堆是比較重要的
10.三種JVM
java -version
- Sun: HotSpot (java Hotspot?64-Bit server vw (build 25.181-b13,mixed mode))
- BEA :JRockit
- IBM: j9VM
- 我們學(xué)習(xí)都是:Hotspot
11.堆(Heap)
一個(gè)JVM只有一個(gè)堆內(nèi)存,堆內(nèi)存的大小是可以調(diào)節(jié)的。
類加載器讀取了類文件后,一般會(huì)把什么東西放到堆中?
類,方法,常量,變量~,保存我們所有引用類型的真實(shí)對(duì)象
堆內(nèi)存中還要細(xì)分為三個(gè)區(qū)域:
- 新生區(qū)(伊甸園區(qū)) Young/New
- 養(yǎng)老區(qū) Old
- 永久區(qū) Perm
GC:Garbage recycling
- 輕GC:輕量級(jí)垃圾回收,主要是在新生區(qū)
- 重GC(Full GC):重量級(jí)垃圾回收,主要是養(yǎng)老區(qū),重GC就說明內(nèi)存都要爆了
GC垃圾回收,主要是在伊甸園區(qū)和養(yǎng)老區(qū)~
假設(shè)內(nèi)存滿了,OOM(Out Of memory),堆內(nèi)存不夠!
java.lang.OutOfMemoryError: Java heap space
在JDK8以后,永久存儲(chǔ)區(qū)改了個(gè)名字(元空間);
12.新生區(qū)、老年區(qū)
新生區(qū):
類誕生和成長(zhǎng)的地方,甚至死亡
- 伊甸園區(qū):所有的對(duì)象都是在伊甸園區(qū)new出來(lái)的
- 幸存(0區(qū),1區(qū))
真理:經(jīng)過研究,99%的對(duì)象都是臨時(shí)對(duì)象!
13.永久區(qū)
這個(gè)區(qū)域常駐內(nèi)存的,用來(lái)存放jdk自身攜帶的class對(duì)象,interface元數(shù)據(jù)
存儲(chǔ)的是Java運(yùn)行時(shí)的一些環(huán)境或類信息
這個(gè)區(qū)域不存在垃圾回收
關(guān)閉虛擬機(jī)就會(huì)釋放這個(gè)區(qū)域的內(nèi)存
一個(gè)啟動(dòng)類,加載了大量的第三方j(luò)ar包,、tomcat部署了太多應(yīng)用,大量動(dòng)態(tài)生成的反射類。不斷地被加載直到內(nèi)存滿,就會(huì)出現(xiàn)OOM;
- jdk1.6以前:永久代,常量池在方法區(qū)
- jdk1.7:永久代,但是慢慢退化了,去永久代,常量池在堆中
- jdk1.8:無(wú)永久區(qū),常量池在元空間
堆:新生區(qū)+老年區(qū)
元空間:非堆(邏輯上存在,物理上不存在)
OOM:
在一個(gè)項(xiàng)目中突然出現(xiàn)了OOM故障,那么如何排除,研究為什么錯(cuò)
- 能夠看到代碼第幾行出錯(cuò):內(nèi)存快照分析工具
- Debug:一行行分析代碼
MAT、Jprofiler的作用:
- 分析Dump內(nèi)存文件,快速定位內(nèi)存泄漏;
- 獲得堆中的數(shù)據(jù)
- 獲得大的對(duì)象
14.堆內(nèi)存調(diào)優(yōu)
Settings–Plugins–JProfiler
JProfiler客戶端官網(wǎng)下載
-Xm:設(shè)置初始化內(nèi)存分配大小,默認(rèn)1/64
-Xmx:設(shè)置最大分配內(nèi)存,默認(rèn) 1/4
-XX:+PrintGCDetails (打印GC垃圾回收信息)
-XX:+HeapDumpOutOfMenoryError(oom Dump)
?
biggest object–Thread Dump–main
15.GC以及常用算法
JVM在進(jìn)行GC時(shí),并不是對(duì)堆中這三個(gè)區(qū)域統(tǒng)一回收,大部分時(shí)候回收都是新生代
GC:垃圾分代收集算法
- 輕GC:
- 重GC:全局GC
GC題目:
- JVM的內(nèi)存模型和分區(qū),詳細(xì)到每個(gè)區(qū)放什么?
- 堆里面的分區(qū)有哪些?Eden、from、to、老年區(qū)、說說他們的特點(diǎn)
- GC算法有哪些?標(biāo)記清除法、標(biāo)記壓縮、復(fù)制算法,引用計(jì)數(shù)器(比較少)怎么用?
- 輕GC和重GC分別在什么時(shí)候發(fā)生?
引用計(jì)數(shù)法:
JVM一般不會(huì)采用這種方式,不高效,計(jì)數(shù)器繁瑣,一個(gè)大項(xiàng)目有很多對(duì)象
復(fù)制算法:
- 好處:沒有內(nèi)存的碎片
- 壞處:浪費(fèi)了內(nèi)存空間,多了一半空間永遠(yuǎn)是空的(浪費(fèi)一個(gè)幸存區(qū))
- 極端情況下:
- 假設(shè)對(duì)象100%存活,把所有拷貝到幸存區(qū),所有地址重新做一遍
- 假設(shè)from區(qū)是滿的,全部復(fù)制到to區(qū),成本很高。
- 復(fù)制算法最佳使用場(chǎng)景:對(duì)象存活度較低的時(shí)候(新生區(qū))
標(biāo)記清除算法:
缺點(diǎn):兩次掃描,嚴(yán)重浪費(fèi)時(shí)間,會(huì)產(chǎn)生內(nèi)存碎片
優(yōu)點(diǎn):不需要額外的空間
標(biāo)記壓縮算法:
優(yōu)點(diǎn):再次掃描,向一端移動(dòng)存活的對(duì)象,防止內(nèi)存碎片產(chǎn)生
缺點(diǎn):又多了一次掃描成本
總結(jié)
- 內(nèi)存效率:復(fù)制算法>標(biāo)記清除算法>標(biāo)記壓縮算法(時(shí)間復(fù)雜度)
- 內(nèi)存整齊度:復(fù)制算法=標(biāo)記壓縮算法>標(biāo)記清除算法
- 內(nèi)存利用率:標(biāo)記壓縮算法=標(biāo)記清除算法>復(fù)制算法
思考一個(gè)問題:難道沒有最優(yōu)算法嗎?
答案:沒有,沒有最好的算法,只有最合適的算法 —>( GC:分代收集算法)
- 分代收集算法:
- 年輕代:存活率低(復(fù)制算法)!
- 老年代:區(qū)域大,存活率高(標(biāo)記清除 (內(nèi)存碎片不是太多) + 標(biāo)記壓縮混合實(shí)現(xiàn)
一天時(shí)間學(xué)JVM,不現(xiàn)實(shí),要深究,必須要下去花時(shí)間,和多看面試題,以及《深入理解JVM》
但是,我們可以掌握一個(gè)學(xué)習(xí)JVM的方法~
16.JMM
1、什么是JMM?
JMM:(Java Memory Model的縮寫):Java內(nèi)存模型【百度百科】
2、它干嘛的?
官方,其他人的博客,對(duì)應(yīng)的視頻!
作用:緩存一致性協(xié)議,用于定義數(shù)據(jù)讀寫的規(guī)則 (遵守,找到這個(gè)規(guī)則)。
JMM定義了線程工作內(nèi)存和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲(chǔ)在主內(nèi)存(Main Memory)中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存(Local Memory),是從主內(nèi)中拷貝的。
解決共享對(duì)象可見性這個(gè)問題: volilate;一旦刷新了就會(huì)很快的同步到主內(nèi)存中。
3、它該如何學(xué)習(xí)?
JMM:抽象的概念,理論
JMM對(duì)這八種指令的使用,制定了如下規(guī)則:
-
不允許read和load、store和write操作之一單獨(dú)出現(xiàn)。即使用了read必須load,使用了store必須write;
-
不允許線程丟棄他最近的assign操作,即工作變量的數(shù)據(jù)改變了之后,必須告知主存;
-
不允許一個(gè)線程將沒有assign的數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存;
-
一個(gè)新的變量必須在主內(nèi)存中誕生,不允許工作內(nèi)存直接使用一個(gè)未被初始化的變量。就是對(duì)變量實(shí)施use、store操作之前,必須經(jīng)過assign和load操作;
-
一個(gè)變量同一時(shí)間只有一個(gè)線程能對(duì)其進(jìn)行l(wèi)ock。多次lock后,必須執(zhí)行相同次數(shù)的unlock才能解鎖;
-
如果對(duì)一個(gè)變量進(jìn)行l(wèi)ock操作,會(huì)清空所有工作內(nèi)存中此變量的值,在執(zhí)行引擎使用這個(gè)變量前,必須重新load或assign操作初始化變量的值;
-
如果一個(gè)變量沒有被lock,就不能對(duì)其進(jìn)行unlock操作。也不能unlock一個(gè)被其他線程鎖住的變量;
-
對(duì)一個(gè)變量進(jìn)行unlock操作之前,必須把此變量同步回主內(nèi)存
JMM對(duì)這八種操作規(guī)則和對(duì)volatile的一些特殊規(guī)則就能確定哪里操作是線程安全,哪些操作是線程不安全的了。但是這些規(guī)則實(shí)在復(fù)雜,很難在實(shí)踐中直接分析。所以一般我們也不會(huì)通過上述規(guī)則進(jìn)行分析。更多的時(shí)候,使用java的happen-before規(guī)則來(lái)進(jìn)行分析。
搜索:JMM面試題
17.總結(jié)
學(xué)習(xí)新東西是常態(tài):
- 如何針對(duì)面試學(xué)習(xí)。
- 如何針對(duì)技術(shù)學(xué)習(xí)。
針對(duì)面試學(xué)習(xí):3/10–pass,總結(jié)面經(jīng),分析這10,再觸類旁通一下:百度面試題
通過大量的面試總結(jié),得出一套解題思路;
學(xué)習(xí)方式:在線畫圖網(wǎng)站推薦搜索
https://www.processon.com/popular?criterion=jvm
百度:JVM參數(shù)(調(diào)優(yōu))+jvm內(nèi)存的年輕代/老年代/持久代
總結(jié)
- 上一篇: jsp中%@ % 与% % 与%! %
- 下一篇: http协议工作流程