您現在的位置是:首頁 > 綜合

深入理解Java虛擬機器:高效併發之執行緒安全與鎖最佳化

  • 由 新手java開發 發表于 綜合
  • 2023-01-11
簡介4.執行緒相容物件或者說方法並不是執行緒安全的,需要呼叫時使用同步手段來保證,如ArrayList、HashMap等

虛擬執行緒作用大嗎

執行緒安全

當多個執行緒同時訪問一個物件時,如果不考慮這些執行緒在執行時環境下的排程和交替執行,也不需要進行額外的同步,或者在呼叫方進行任何其他的協調操作,呼叫這個物件的行為都可以獲得正確的結果。

Java中的執行緒安全

1.不可變

不可變的物件一定是執行緒安全的,無論是物件的方法實現還是方法的呼叫者,都不需要再進行任何執行緒安全保障措施。

如果多執行緒共享資料是一個基本資料型別,只要在定義時使用final關鍵字修飾 它就可以保證。

如果共享資料是一個物件,那就需要物件自行保證,如String類物件例項,無論是什麼方法都不會影響它原來的值,返回一個新構造的字串物件。

2.絕對執行緒安全

Java API中目前沒有覺得的執行緒安全。比如Vector

深入理解Java虛擬機器:高效併發之執行緒安全與鎖最佳化

以上程式碼,就不是絕對的執行緒安全,雖然使用的Vector的get()、remove()和size()方法都是同步的。但是如果另一個執行緒恰好某個時間刪除了一個元素,導致i下標下的元素不存在,在進行get訪問的話,就會丟擲ArrayIndexOutOfBoundException異常。

3.相對執行緒安全

比如上面的Vector就是,get、remove、size等方法只能保證在該方法內的執行緒絕對安全(使用了synchronized關鍵字),但是對於整個的程式就只能說明是相對執行緒安全。

Vector、HashTable、Collections下synchronizedCollection等都是如此。

4.執行緒相容

物件或者說方法並不是執行緒安全的,需要呼叫時使用同步手段來保證,如ArrayList、HashMap等。

5.執行緒對立

不管呼叫端是否採取了同步措施,都無法再多執行緒環境中併發使用程式碼。

比如,Thread類的suspend()和resume()方法。如果有兩個執行緒同時持有一個執行緒物件,一個嘗試去中斷執行緒,一個嘗試去恢復執行緒,在併發進行的情況下,無論呼叫時是否進行了同步,目標執行緒都存在死鎖的風險。

執行緒安全的實現方法

1。互斥(阻塞)同步

互斥同步是一種最常見也是最主要的併發正確性保障手段。同步是指在多個執行緒併發訪問共享資料時,保證共享資料在同一時刻只被一條(或者是一些,當使用訊號量的時候)執行緒使用。而互斥是實現同步的一種手段,臨界區、互斥量和訊號量都是常見的互斥實現方式。

synchronized

被synchronized修飾的同步塊對同一條執行緒來說是可重入的。

被synchronized修飾的同步塊在持有鎖的執行緒執行完畢並釋放鎖之前,會無條件地阻塞後面其他執行緒的進入。

ReentrantLock

等待可中斷:是指當持有鎖的執行緒長期不釋放所的時候,正在等待的執行緒可以選擇放棄等待,改為處理其他事情。

公平鎖:是指多個執行緒在等待同一個鎖時,必須按照申請鎖的時間順序來依次獲得鎖;而非公平鎖則不保證這一點,在鎖被釋放時,任何一個等待鎖的執行緒都有機會獲得鎖。

鎖繫結多個條件:是指一個ReentrantLock物件可以同時繫結多個Condition物件。

2。非阻塞同步

CAS:比較並交換;CAS指令需要有三個運算元,分別是記憶體位置V,舊的預期值A和準備設定的新值B。CAS指令執行時,當且僅當V符合A時,處理器才會用B更新V的值,否則就不執行更新。

無法解決的場景:ABA問題

3。無同步方案

可重入程式碼:不依賴全域性變數、存在在堆上的資料和公共的系統資源,用到的狀態量都是由引數中傳入,不呼叫非可重入的方法。

執行緒本地儲存:生產者-消費者模式

鎖最佳化

自旋鎖:避免了執行緒切換的開銷,但是要佔用處理器時間;自適應自旋是由前一次在同一個鎖上的自旋時間及鎖擁有者的狀態來決定的。

鎖消除:虛擬機器即時編譯器在執行時,對一些程式碼要求同步,但是對檢測到不可能存在共享資料競爭的鎖進行消除;主要判定依據是逃逸分析的資料支援,如果判斷一段程式碼中,在堆上的所有資料都不會逃逸出去被其他下次呢很那個訪問到,那就可以把它們當做棧上資料對待,認為它們是執行緒私有的,同步加鎖就無意義了。

鎖粗化:如果虛擬機器探測到一串零碎的操作都對同一個物件加鎖,將會把加鎖同步的範圍粗化到整個操作序列的外部。

輕量級鎖:在沒有多執行緒競爭的前提下,減少重量級鎖使用作業系統互斥量產生的效能消耗。

偏向鎖:消除資料在無競爭情況下的同步,進一步提高程式的執行效能。

輕量級鎖的工作過程

深入理解Java虛擬機器:高效併發之執行緒安全與鎖最佳化

程式碼即將進入同步塊的時候,如果此同步沒有被鎖定(鎖標誌位為01),虛擬機器首先將在當前執行緒的棧幀中建立一個鎖記錄的空間,用於儲存鎖物件目前的Mark Word的賦值。

然後虛擬機器將使用CAS操作嘗試把物件的Mark Word更新為指向所記錄的指標,如果更新成功,則代表該執行緒擁有了這個物件的鎖,並且物件Mark Word的鎖標誌位變成00。

如果更新失敗,則意味著存線上程與當前執行緒競爭獲取該物件的鎖。

虛擬機器會繼續檢查物件的Mark Word是否指向當前執行緒的棧幀。如果是,則說明擁有該物件鎖。

否則說明這個鎖物件已經被其他執行緒佔用。

如果有兩條以上的執行緒競爭同一個鎖,那輕量級鎖要膨脹為重量級鎖,鎖標誌位變為10,等待鎖的執行緒也會進入阻塞狀態。

深入理解Java虛擬機器:高效併發之執行緒安全與鎖最佳化

Top