導(dǎo)讀
- 移動開發(fā)知識體系總章(Java基礎(chǔ)、Android糊余、Flutter)
- Java四大引用類型
- 公平鎖秀又、非公平鎖
- 樂觀鎖、悲觀鎖
- 獨享鎖贬芥、共享鎖
- 互斥鎖
- 分段鎖
- 偏向鎖
- 自旋鎖
公平鎖吐辙、非公平鎖
- 公平鎖是指多個線程在等待同一個鎖時,必須按照申請鎖的先后順序來一次獲得鎖蘸劈。
- 公平鎖的好處是等待鎖的線程不會餓死昏苏,但是整體效率相對低一些;
- 非公平鎖的好處是整體效率相對高一些威沫,但是有些線程可能會餓死或者說很早就在等待鎖捷雕,但要等很久才會獲得鎖。
- 其中的原因是公平鎖是嚴(yán)格按照請求所的順序來排隊獲得鎖的壹甥,而非公平鎖時可以搶占的,即如果在某個時刻有線程需要獲取鎖壶熏,而這個時候剛好鎖可用句柠,那么這個線程會直接搶占,而這時阻塞在等待隊列的線程則不會被喚醒棒假。
- 公平鎖可以使用new ReentrantLock(true)實現(xiàn)溯职。
對于Java ReentrantLock和而言,通過構(gòu)造函數(shù)指定該鎖是否是公平鎖帽哑,默認(rèn)是非公平鎖谜酒。非公平鎖的優(yōu)點在于吞吐量比公平鎖大。
對于Synchronized而言妻枕,也是一種非公平鎖僻族。由于其并不像ReentrantLock是通過AQS的控制線程對鎖的獲取粘驰, 所以并沒有任何辦法使其變成公平鎖。
互斥鎖/讀寫鎖
上面講的獨享鎖/共享鎖就是一種廣義的說法述么,互斥鎖/讀寫鎖就是具體的實現(xiàn)蝌数。
互斥鎖在Java中的具體實現(xiàn)就是ReentrantLock
讀寫鎖在Java中的具體實現(xiàn)就是ReadWriteLock
可重入鎖
可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候度秘,在進入內(nèi)層方法會自動獲取鎖顶伞。說的有點抽象,下面會有一個代碼的示例剑梳。
對于Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖唆貌,其名字是Re entrant Lock重新進入鎖。
對于Synchronized而言,也是一個可重入鎖垢乙∠橇可重入鎖的一個好處是可一定程度避免死鎖。
樂觀鎖侨赡、悲觀鎖
樂觀鎖/悲觀鎖不是指具體類型的鎖蓖租,而是看待并發(fā)的角度。
- 悲觀鎖是假定會發(fā)生并發(fā)沖突羊壹,屏蔽一切可能違反數(shù)據(jù)完整性的操作蓖宦。
- 樂觀鎖是假定不會發(fā)生并發(fā)沖突,只在提交操作時檢測是否違反數(shù)據(jù)完整性油猫。(使用版本號或者時間戳來配合實現(xiàn))稠茂。
獨享鎖、共享鎖
- 獨享鎖是指該鎖一次只能被一個線程所持有情妖。
- 共享鎖是指該鎖可被多個線程所持有睬关。
對于Java ReentrantLock而言,其是獨享鎖毡证。但是對于Lock的另一個實現(xiàn)類ReadWriteLock电爹,其讀鎖是共享鎖,其寫鎖是獨享鎖料睛。
讀鎖的共享鎖可保證并發(fā)讀是非常高效的丐箩,讀寫,寫讀 恤煞,寫寫的過程是互斥的屎勘。
獨享鎖與共享鎖也是通過AQS來實現(xiàn)的,通過實現(xiàn)不同的方法居扒,來實現(xiàn)獨享或者共享概漱。
對于Synchronized而言,當(dāng)然是獨享鎖喜喂。
分段鎖
分段鎖其實是一種鎖的設(shè)計瓤摧,并不是具體的一種鎖竿裂,對于ConcurrentHashMap而言,其并發(fā)的實現(xiàn)就是通過分段鎖的形式來實現(xiàn)高效的并發(fā)操作姻灶。
我們以ConcurrentHashMap來說一下分段鎖的含義以及設(shè)計思想铛绰,ConcurrentHashMap中的分段鎖稱為Segment,它即類似于HashMap(JDK7與JDK8中HashMap的實現(xiàn))的結(jié)構(gòu)产喉,即內(nèi)部擁有一個Entry數(shù)組捂掰,數(shù)組中的每個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)曾沈。
當(dāng)需要put元素的時候这嚣,并不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在那一個分段中塞俱,然后對這個分段進行加鎖姐帚,所以當(dāng)多線程put的時候爬早,只要不是放在一個分段中霉晕,就實現(xiàn)了真正的并行的插入。
但是位迂,在統(tǒng)計size的時候唯蝶,可就是獲取hashmap全局信息的時候九秀,就需要獲取所有的分段鎖才能統(tǒng)計。
分段鎖的設(shè)計目的是細(xì)化鎖的粒度粘我,當(dāng)操作不需要更新整個數(shù)組的時候鼓蜒,就僅僅針對數(shù)組中的一項進行加鎖操作。
偏向鎖/輕量級鎖/重量級鎖
這三種鎖是指鎖的狀態(tài)征字,并且是針對Synchronized都弹。在Java 5通過引入鎖升級的機制來實現(xiàn)高效Synchronized。這三種鎖的狀態(tài)是通過對象監(jiān)視器在對象頭中的字段來表明的匙姜。
偏向鎖是指一段同步代碼一直被一個線程所訪問畅厢,那么該線程會自動獲取鎖。降低獲取鎖的代價氮昧。
輕量級鎖是指當(dāng)鎖是偏向鎖的時候或详,被另一個線程所訪問,偏向鎖就會升級為輕量級鎖郭计,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞椒振,提高性能昭伸。
重量級鎖是指當(dāng)鎖為輕量級鎖的時候,另一個線程雖然是自旋澎迎,但自旋不會一直持續(xù)下去庐杨,當(dāng)自旋一定次數(shù)的時候选调,還沒有獲取到鎖,就會進入阻塞灵份,該鎖膨脹為重量級鎖仁堪。重量級鎖會讓其他申請的線程進入阻塞,性能降低填渠。
自旋鎖
在Java中弦聂,自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖氛什,這樣的好處是減少線程上下文切換的消耗莺葫,缺點是循環(huán)會消耗CPU。