鎖機制初探(一)Java虛擬機同步機制簡介

轉載地址:https://blog.csdn.net/w372426096/article/details/80938901

想介紹下synchronized的原理,但是又不知道從何下手,在網上看到一篇老外的文章,介紹了和線程同步相關的幾個基礎知識點。所以想把它翻譯一下給大家看看。相信看過這些基礎知識之後再看我後面要寫的synchronized的原理就會好理解一點了。


原文地址:How the Java virtual machine performs thread synchronization

瞭解Java語言的人都知道,Java代碼要想被JVM執行,需要被轉換成由字節碼組成的class文件。本文主要來分析下Java虛擬機是如何在字節碼層面上執行線程同步的。

線程和共享數據

Java編程語言的優點之一是它在語言層面上對多線程的支持。這種支持大部分集中在協調多個線程對共享數據的訪問上。JVM的內存結構主要包含以下幾個重要的區域:棧、堆、方法區等。

在Java虛擬中,每個線程獨享一塊棧內存,其中包括局部變量、線程調用的每個方法的參數和返回值。其他線程無法讀取到該棧內存塊中的數據。棧中的數據僅限於基本類型和對象引用。所以,在JVM中,棧上是無法保存真實的對象的,只能保存對象的引用。真正的對象要保存在堆中。

在JVM中,堆內存是所有線程共享的。堆中只包含對象,沒有其他東西。所以,堆上也無法保存基本類型和對象引用。堆和棧分工明確。但是,對象的引用其實也是對象的一部分。這裏值得一提的是,數組是保存在堆上面的,即使是基本類型的數據,也是保存在堆中的。因爲在Java中,數組是對象。

除了棧和堆,還有一部分數據可能保存在JVM中的方法區中,比如類的靜態變量。方法區和棧類似,其中只包含基本類型和對象應用。和棧不同的是,方法區中的靜態變量可以被所有線程訪問到。

對象和類的鎖

如前文提到,JVM中有兩塊內存區域可以被所有線程共享:

堆,上面存放着所有對象

方法區,上面存放着靜態變量

那麼,如果有多個線程想要同時訪問同一個對象或者靜態變量,就需要被管控,否則可能出現不可預期的結果。

爲了協調多個線程之間的共享數據訪問,虛擬機給每個對象和類都分配了一個鎖。這個鎖就像一個特權,在同一時刻,只有一個線程可以“擁有”這個類或者對象。如果一個線程想要獲得某個類或者對象的鎖,需要詢問虛擬機。當一個線程向虛擬機申請某個類或者對象的鎖之後,也許很快或者也許很慢虛擬機可以把鎖分配給這個線程,同時這個線程也許永遠也無法獲得鎖。當線程不再需要鎖的時候,他再把鎖還給虛擬機。這時虛擬機就可以再把鎖分配給其他申請鎖的線程。

類鎖其實通過對象鎖實現的。因爲當虛擬機加載一個類的時候,會會爲這個類實例化一個 java.lang.Class 對象,當你鎖住一個類的時候,其實鎖住的是其對應的Class 對象。

監視器(Monitors)

監視器和鎖同時被JVM使用(我理解作者的意思應該是想說鎖其實是通過監視器實現的。),監視器主要功能是監控一段代碼,確保在同一時間只有一個線程在執行。

每個監視器都與一個對象相關聯。當線程執行到監視器監視下的代碼塊中的第一條指令時,線程必須獲取對被引用對象的鎖定。在線程獲取鎖之前,他是無法執行這段代碼的,一旦獲得鎖,線程便可以進入“被保護”的代碼開始執行。

當線程離開代碼塊的時候,無論如何離開,都會釋放所關聯對象的鎖。

多次加鎖

同一個線程可以對同一個對象進行多次加鎖。每個對象維護着一個記錄着被鎖次數的計數器。未被鎖定的對象的該計數器爲0,當一個線程獲得鎖後,該計數器自增變爲 1 ,當同一個線程再次獲得該對象的鎖的時候,計數器再次自增。當同一個線程釋放鎖的時候,計數器再自減。當計數器爲0的時候。鎖將被釋放,其他線程便可以獲得鎖。

同步

在Java中,當有多個線程都必須要對同一個共享數據進行訪問時,有一種協調方式叫做同步。Java語言提供了兩種內置方式來使線程同步的訪問數據:同步代碼塊和同步方法。

這篇文章中後面還介紹了同步代碼塊和同步方法,以及簡單的介紹了下實現方式。這裏就不做翻譯了,因爲我覺得他介紹的太簡單了。我後面專門寫篇文章詳細介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章