我们如何才能让锁变得更好用?
- 鎖偏向
? ? ?是一種加鎖操作的優(yōu)化手段,他的核心思想是:如果一個(gè)線程獲得了鎖,那么就進(jìn)入偏向模式,當(dāng)這個(gè)線程再次請(qǐng)求鎖時(shí),無須在做任何同步操作,因此在幾乎沒有鎖競爭的場合,偏向鎖是比較好的優(yōu)化效果,因?yàn)檫B續(xù)多次極有可能是同一個(gè)線程請(qǐng)求同一個(gè)相同的鎖,對(duì)于鎖競爭比較激烈的場合,其效果不佳,因?yàn)楦偁幖ち业膱龊?最有可能的情況是每次都是不同的線程來請(qǐng)求相同的鎖,這樣偏向模式就會(huì)失效,使用Java虛擬機(jī)參數(shù)-XX:+UseBiasedLocking可以開啟偏向鎖,
- 輕量級(jí)鎖
? ? ?如果偏向鎖失敗,虛擬機(jī)并不會(huì)立即掛起線程,他還會(huì)使用一種稱為輕量級(jí)鎖的優(yōu)化手段,輕量級(jí)鎖的操作也很方便,它只是簡單地將對(duì)象頭部作為指針,指向持有鎖的線程堆棧內(nèi)部,來判斷一個(gè)線程是否持有對(duì)象鎖,如果線程獲取輕量級(jí)鎖成功,則可以順利進(jìn)入臨界區(qū),如果輕量級(jí)鎖加鎖失敗,則表示其他線程搶險(xiǎn)爭奪到了鎖,那么當(dāng)前線程的鎖請(qǐng)求就會(huì)膨脹為重量級(jí)鎖
- 自旋鎖
? ? ?鎖膨脹后,虛擬機(jī)為了避免線程真實(shí)的在操作系統(tǒng)層面掛起,虛擬機(jī)還會(huì)在做最后的努力,自旋鎖,由于當(dāng)前線程暫時(shí)無法獲得鎖,但什么時(shí)候可以獲得鎖是一個(gè)未知數(shù),也許幾個(gè)cpu時(shí)鐘周期,就可以得到鎖,如果這樣,簡單粗暴地掛起線程可能是一種得不償失的操作,因此,系統(tǒng)會(huì)進(jìn)行一次賭注,他會(huì)假設(shè)在不久的將來,線程可以得到這把鎖,因此,虛擬機(jī)會(huì)讓當(dāng)前線程做幾個(gè)空循環(huán),在經(jīng)過若干次循環(huán)后,如果可以得到鎖,那么就順利進(jìn)入臨界區(qū),如果還是得不到鎖,才會(huì)真實(shí)地將線程在操作系統(tǒng)層面掛起,
- 鎖消除
? ? ?鎖消除是一種更徹底的鎖優(yōu)化,Java虛擬機(jī)在Jit編譯時(shí),通過對(duì)運(yùn)行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過鎖消除,可以節(jié)省毫無意義的請(qǐng)求鎖的時(shí)間,如果不可能存在競爭,為什么還要加鎖呢?這是因?yàn)檎ava軟件開發(fā)過程中,我們必然會(huì)使用一些JDK的內(nèi)置API,比如StringBuffer,Vector等,你在使用的時(shí)候,也許根本不會(huì)考慮這些對(duì)象內(nèi)部是如何實(shí)現(xiàn)的,但是真實(shí)環(huán)境中,缺不存在競爭,如果虛擬機(jī)檢測到這種情況,就會(huì)將這些無用的鎖操作去除,
public String[] createStrings() {Vector<String> v = new Vector<>();for (int i = 0; i < 100; i++) {v.add(Integer.toString(i));}return v.toArray(new String[]{}); }? ? ?鎖消除涉及一項(xiàng)關(guān)鍵技術(shù)為逃逸分析,所謂逃逸分析就是觀察某一個(gè)變量是否會(huì)逃出某一個(gè)作用域,在本例子中,變量v顯然沒有逃出createStrings()方法之外,以此為基礎(chǔ),虛擬機(jī)才可以大膽地將v內(nèi)部的加鎖操作去除,
? ? ?逃逸分析必須在-server模式下進(jìn)行,可以使用-XX:+DoEscapeAnalysis參數(shù)打開逃逸分析.使用-XX:+EliminateLocks參數(shù)可以打開鎖消除.
在寫代碼時(shí)如何優(yōu)化鎖和提高并發(fā)性能
- 縮小同步代碼塊
- 盡量不要鎖住方法
- 減少鎖的次數(shù)
- 避免人為制造“熱點(diǎn)”
- 鎖中盡量不要包含鎖
- 選擇合適的鎖類型或合適的工具類
?
總結(jié)
以上是生活随笔為你收集整理的我们如何才能让锁变得更好用?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。