高并發(fā)下如何合理使用鎖

在并發(fā)環(huán)境下想要共享變量,一旦涉及修改操作,就需要用到鎖了。
Java 中的鎖有這么幾種:synchronizedreentrant lock、還有reentrant lock 衍生出的其他鎖比如ReadWriteReentrantLock

鎖性能比較:

這幾種鎖在爭用量級不同的情況下性能是不同的,就synchronized、ReentrantLock來分析比較的話,看到網(wǎng)上有好多博客都在說sychronized 在爭用頻次非常高的情況下性能會急劇下降,這種觀點是存在時效性的,就當前1.8版本使用體驗而言,sychronized在大量爭用的情況性能其實還好并不會出現(xiàn)所謂的急劇下降,倒是在激烈爭用時sychronized的性能要好一些,這個問題去官網(wǎng)確認了下,就現(xiàn)狀而言官方是建議使用sychronized的,這次的體驗也是sychronized更好。因為當前JVM是對于sychronized做出了優(yōu)化了,借鑒ReentrantLock的CAS加鎖方式,并且引入了偏向鎖、輕量級鎖等特性后,常規(guī)情況下兩者比較相似,實踐中得到的體驗是sychronized性能更好一點,可能是JVM層面加鎖之后,并且編譯器同時做優(yōu)化Sychronized 更適合在用戶態(tài)把加鎖問題解決避免陷入內(nèi)核態(tài)的線程阻塞更有用吧。

鎖粒度:

synchronized 所支持的鎖粒度相較于ReentrantLock來說是處于劣勢的,但是對于大多數(shù)場景來說synchronized足夠用了。

鎖特性:

synchronized 支持的一些偏向鎖只能說是性能上的特性不能算是功能上的,但是加鎖方便,不需要顯示加鎖釋放鎖,不容易產(chǎn)生死鎖,代碼編寫簡單(編寫簡單這事兒并不是很在意,目的是提升性能)
ReentrantLock 特性就比較豐富了,支持公平鎖、鎖超時,更大程度上避免了死鎖,但是ReentrantLock 能夠控制的粒度更細,并且衍生出來的工具十分好用,比如說讀寫鎖,但是也產(chǎn)生了需要手動釋放鎖這個問題。
其他鎖相關的基礎知識,可以看一下我博客Java Concurrent系列的文章,這里就不過多贅述了。
這里重點要說的是使用鎖的一些方式:

1、鎖選擇

鑒于上面性能比較的結(jié)果,推薦使用sychronized

2、鎖粒度

粒度要盡可能的控制到小,避免不必要的加鎖。因為同步塊越長,線程持有鎖的時間就越長,其他線程等待的時間就越長,如果整個都是加鎖的,那么整個程序就變成串行處理了。

3、避免加鎖

一些能夠犧牲空間來進行ThreadLocal處理的,就沒必要使用鎖了,加鎖完全是為了并發(fā)下邏輯的正確,如果有更好的解決方式,請避免使用鎖,但是如果像是一些非得使用鎖的情況,也務必主要鎖的粒度,像是直接給函數(shù)加鎖,實在是不應該。

4、減少部分加鎖

比如限流計數(shù)器,我們需要先判定是否大于0再決定是否進行減一操作,這是經(jīng)典的競態(tài)條件,按理說應該是加鎖的,但是如果一共就200個線程爭用,我們就可以合理的控制了,count 初始值為1000,假設每個線程只發(fā)起一次請求,我們要保證的是count不會減到0以下,我們前800次其實是沒必要進行同步處理的,只需要用下原子類就可以了。之后后面100多次再產(chǎn)生同步就好了。

5、相關并發(fā)工具的選擇

在高qps下使用Concurrent 包下的工具時,一定要先知道原理或者看看源碼再使用,切不可盲目使用因為很多工具一些特性是沒有用的但是為了這些特性增加了很多額外的加鎖操作。然后也要知道如果有剛好符合你的需求,一定要用API 這樣才能得到更好的性能及更大的正確性保證。

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

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

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