Java并發(fā)編程-鎖優(yōu)化


參考資料:《實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)》


1.鎖優(yōu)化的幾個(gè)方面

1.減少鎖持有時(shí)間

  • 減少鎖的持有時(shí)間有助于降低鎖沖突的可能性,進(jìn)而提升系統(tǒng)的并發(fā)能力。

2.減小鎖粒度

  • 減少鎖粒度,是指縮小鎖定對象的范圍,從而減少鎖沖突的可能性,進(jìn)而提升系統(tǒng)的并發(fā)能力。
  • 但要注意,減少鎖粒度會引入一個(gè)新的問題,即:當(dāng)系統(tǒng)需要取得全局鎖時(shí),其消耗的資源會比較多。所以只有當(dāng)獲取全局信息的方法調(diào)用并不頻繁時(shí),這種減少鎖粒度的方法才能真正意義上提供系統(tǒng)吞吐量。

3.讀寫分離鎖來替換獨(dú)占鎖

  • 使用讀寫分離鎖來替換獨(dú)占鎖是減少鎖粒度的一種特殊情況。
  • 如果說減少鎖粒度是通過分割數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,那么讀寫鎖則是對系統(tǒng)功能點(diǎn)的分割。
  • 因讀操作本身不會影響數(shù)據(jù)的完整性和一致性,所以讀操作本就該是被準(zhǔn)許同時(shí)執(zhí)行的。
  • 讀多寫少的場合,使用讀寫鎖可以提升系統(tǒng)的并發(fā)能力。

4.鎖分離

  • 將讀寫鎖的思想做進(jìn)一步的延伸,就是鎖分離。讀寫鎖根據(jù)根據(jù)讀寫操作功能的不同,進(jìn)行了有效的鎖分離。依據(jù)應(yīng)用的功能特點(diǎn),使用類似的分離思想,也可以對獨(dú)占鎖進(jìn)行分離
  • 例如LinkedBlockingQueue,就是通過takeLockputLock兩把鎖,實(shí)現(xiàn)了取數(shù)據(jù)和寫數(shù)據(jù)的分離,使兩者在真正意義上成為并發(fā)的操作。

5.鎖粗化

  • 通常,為了保證多線程間的有效并發(fā),會要求每個(gè)線程持有鎖的時(shí)間盡量短。但凡事有個(gè)度,如果對同一個(gè)鎖不停的進(jìn)行 請求、同步和釋放,其本身也會消耗寶貴的資源。反而不利于性能優(yōu)化。
  • 因此,虛擬機(jī)在遇到一連串連續(xù)的對同一鎖的請求和釋放操作時(shí),便會把所有鎖操作整合成對鎖的一次請求,從而減少對鎖的請求次數(shù),這個(gè)操作叫做鎖的粗化
  • 例如:
for(int i=0;i<CIRCLE;i++){
    synchronized(lock){
    
    }
}
  • 就應(yīng)該改成只在最外層請求一次鎖:
synchronized(lock){
    for(int i=0;i<CIRCLE;i++){
    
    }
}
  • 性能的優(yōu)化是根據(jù)運(yùn)行時(shí)的真實(shí)情況對各個(gè)資源點(diǎn)進(jìn)行權(quán)衡折中的過程。鎖粗化的思想和減少鎖持有時(shí)間是相反的,需要根據(jù)實(shí)際情況進(jìn)行權(quán)衡。

2.JVM內(nèi)部的鎖優(yōu)化策略

1.鎖偏向

  • 鎖偏向是一種針對加鎖操作的優(yōu)化手段。它的思想是:如果一個(gè)線程獲得了鎖,那么鎖就進(jìn)入偏向模式。當(dāng)這個(gè)線程再次請求鎖時(shí),無須再做任何同步操作。這樣就節(jié)省了大量有關(guān)鎖申請的操作,從而提高了程序性能。
  • 因此,對于幾乎沒有鎖競爭的場合,偏向鎖有較好的優(yōu)化效果。而對于鎖競爭比較激烈的場合,則效果不佳。
  • 使用Java虛擬機(jī)參數(shù)-XX:+UseBiasedLocking可以開啟偏向鎖。

2.輕量級鎖

  • 如果偏向鎖失敗,虛擬機(jī)并不會立即掛起線程。它會使用一種稱為輕量級鎖的優(yōu)化手段。
  • 輕量級鎖只是簡單地將對象頭部作為指針,指向持有鎖的線程堆棧的內(nèi)部,來判斷一個(gè)線程是否持有對象鎖。
  • 如果線程獲得輕量級鎖成功,則可以順利進(jìn)入臨界區(qū)。否則表示其他線程搶先爭奪到了鎖,那么當(dāng)前線程的鎖請求就會膨脹重量級鎖。

3.自旋鎖

  • 鎖膨脹后,虛擬機(jī)為了避免線程真實(shí)地在操作系統(tǒng)層面掛起,還會做最后的努力——自旋鎖。
  • 由于當(dāng)前線程暫時(shí)無法獲得鎖,但什么時(shí)候可以獲得還是未知數(shù),也許在幾個(gè)CPU時(shí)鐘周期后,就可以獲得,那簡單粗暴地掛起線程可能就是得不償失的。因此,系統(tǒng)會進(jìn)行一次賭注:它會假設(shè)在不久的將來,線程可以得到這把鎖。因此虛擬機(jī)會讓當(dāng)前線程做幾個(gè)空循環(huán)(即 自旋),在經(jīng)過若干次自旋后,如果可以得到鎖,那么就順利進(jìn)入臨界區(qū)。如果還不能獲得鎖,才會真實(shí)地將線程在操作系統(tǒng)層面掛起。

4.鎖消除

  • 鎖消除是指JVM在進(jìn)行JIT編譯時(shí),通過對運(yùn)行上下文的掃描,去除不可能存在共享資源競爭的鎖。通過鎖消除,可以節(jié)省毫無意義的請求鎖時(shí)間。
  • 一個(gè)鎖消除發(fā)生的場景比如:對一個(gè)方法體內(nèi)的局部變量,使用了線程安全的類型(例如StringBuffer、Vector)。如果虛擬機(jī)檢測到這種情況,就會將這些無用的鎖操作去除。
  • 鎖消除涉及的一項(xiàng)關(guān)鍵技術(shù)為逃逸分析。所謂逃逸分析,是指觀察某一個(gè)變量是否會逃出某個(gè)作用域。
  • 逃逸分析必須在-server模式下進(jìn)行,可以使用-XX:+DoEscapeAnalysis參數(shù)打開逃逸分析。使用-XX:+EliminateLocks參數(shù)可以打開鎖消除。

end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容