☕【JVM技術探索】深入分析各種鎖(鎖膨脹)運作流程

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"前提承接","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"針對於之前兩篇關於synchronized的文章,主要介紹關於synchronized在字節碼中的實現方式和表現形式(同步代碼塊和同步方法)","attrs":{}},{"type":"link","attrs":{"href":"https://my.oschina.net/liboware/blog/5054980","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Java併發編程專題系列之深入分析synchronized(基礎篇)","attrs":{}}]},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"以及先關針對於同步鎖的實現原理比如ObjectMonitor的數據結構以及等待隊列和同步隊列等","attrs":{}},{"type":"link","attrs":{"href":"https://my.oschina.net/liboware/blog/5059359","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Java併發編程專題系列之深入分析synchronized(進階篇)","attrs":{}}]},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":",本文主要介紹針對於在執行角度包含對象鎖的結構(標記字段的狀態)和相關加鎖過程進行相關的流程梳理以及對前兩章的總結","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"synchronized關鍵字","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"synchronized的鎖機制的主要優勢是Java語言內置的鎖機制,因此,JVM可以自由的優化而不影響已存在的代碼","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"任何對象都擁有對象頭這一數據結構來支持鎖,但是對於較大的對象系統開銷會更大一些。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"java","attrs":{}},{"type":"text","text":"中的每一個對象都至少包含2個字(","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2 * 4 Bytes for 32bits & 2 * 8 Bytes for 64bits, 不包括已壓縮的對象","attrs":{}},{"type":"text","text":")。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第一個字被稱爲Mark Word。這是一個對象的頭,它包含了不同的信息,包括鎖的相關信息","attrs":{}},{"type":"text","text":"(32bitOS->8bit大小、64bitOS->16bit大小)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第二個字是指向metadata class的指針,metadata class字義了對象的類型。這部分也包含了VMT(Virtual Method Table)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Mark Word 的結構如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/14/140a62469f5ab8397a6568eba9bdde11.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Mark Word根據最低兩位(Tag)的所表示的對象狀態(包含了鎖的類型),編碼了不同的信息","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果這個對象沒有被用作鎖,Mark Word 記錄了hashcode和對象年齡(for GC/survivors)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除此之外,有3種狀態對應鎖:輕量級鎖,重量級鎖和偏向鎖。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"輕量級鎖","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"現代JVM都引入了輕量級鎖","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"避免將每個對象關聯操作系統的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"mutex/condition","attrs":{}},{"type":"text","text":"變量(","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"重量級鎖","attrs":{}},{"type":"text","text":")","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"當不存在鎖競爭時,使用原子操作來進入退出同步塊","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果發生鎖競爭,回退到操作系統的重量級鎖","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"引入輕量級鎖會提供鎖效率,因爲大部分鎖都不存在競爭","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"輕量級鎖的加鎖過程","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"當一個對象被鎖定時,mark word被複制到當前嘗試獲取鎖的線程的線程棧(Execution stack)的鎖記錄空間(lock record), 被複制的mark word官方稱爲displaced mark","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用CAS操作來嘗試使","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"mark word","attrs":{}},{"type":"text","text":"指向當前線程的鎖記錄空間(即在mark word中存入使用","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"當前線程鎖記錄空間的指針——stack pointer","attrs":{}},{"type":"text","text":")。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果CAS操作成功,則線程獲得鎖","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果CAS操作失敗,即存在鎖競爭,則發生鎖膨脹,回退到重量級鎖","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"鎖記錄空間中記錄了被當前執行方法鎖定的對象(通過遍歷線程棧找到線程的鎖對象)。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"輕量級鎖加鎖前:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/36/36ae9887c061edd4025752f2434ebeaa.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"輕量級鎖加鎖後:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e8/e8b9c4011a426d5dd482b5b7dbe8f61a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"經量級鎖的解鎖過程:","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"解鎖使用CAS來把","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"displaced mark","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"寫回對象的mark word中","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果CAS失敗, 表示發生鎖競爭:則鎖膨脹。(通知其他等待線程鎖已釋放)將鎖記錄空間置爲0","attrs":{}},{"type":"text","text":";","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果發生鎖膨脹,則用0替換","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"displaced mark","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":",如果不存在競爭,則CAS將鎖記錄空間置爲0後,停止CAS操作","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"偏向鎖","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向鎖的引入","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在多處理器上CAS操作可能開銷很大。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"大多數鎖不僅不存在競爭,而且往往由同一個線程使用。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"使單獨一個線程獲取鎖的開銷更低。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"代價是使另一個線程獲取鎖開銷增大。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向鎖加鎖過程","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"鎖對象第一次被線程獲取時,VM把對象頭中的標誌位設爲101,即偏向模式","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"同時使用CAS把獲取到這個鎖的線程ID記錄在對象的mark word中,如果CAS成功,則持有偏向鎖的線程以後每次進行這個鎖相關的同步塊時,不再進行任務同步操作,只進行比較Mark word中的線程ID是否是當前線程的ID","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向鎖的解鎖過程","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"當另外一個線程去嘗試獲取這個鎖時,偏向模式結束。根據鎖對象目前是否處於被鎖定狀態,撤銷偏向後恢復到未鎖定或輕量級鎖定狀態","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"VM會停止持有偏向鎖的線程(實際上,VM不能停止單一線程,而是在安全點進行的操作)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"遍歷持有偏向鎖的線程的棧,找到鎖記錄空間,將displaced mark 寫入到最舊的鎖記錄空間,其他的寫0","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"更新鎖對象的mark word。如果被鎖定,則指向最舊的鎖記錄空間,否則,填入未鎖定值。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向鎖的特點:","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"偏向於第一個獲取鎖的線程:","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"mark word","attrs":{}},{"type":"text","text":"的Tag中增加一位","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"001表示無鎖狀態\n101表示偏向或可偏向狀態(thread ID ==0 == unlock)\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"通過CAS來獲取偏向鎖","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"對於持有鎖的線程接下的鎖獲取和釋放開銷非常小(僅僅判斷下,不需要CAS同步操作)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果另一個線程鎖定了偏向鎖對象,則偏向鎖收回,升級爲輕量級鎖(增加了另一個線程獲取鎖的開銷)。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章