公平鎖/非公平鎖算法
可重入鎖編程
獨享鎖/共享鎖數組
互斥鎖/讀寫鎖多線程
樂觀鎖/悲觀鎖併發
分段鎖函數
偏向鎖/輕量級鎖/重量級鎖性能
自旋鎖
spa
這些鎖的種類並非全是指鎖的狀態,有的指鎖的特性,有的指鎖的設計線程
公平鎖/非公平鎖設計
公平鎖是指多個線程按照申請鎖的順序來獲取鎖。 非公平鎖是指多個線程獲取鎖的順序並非按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。有可能,會形成優先級反轉或者飢餓現象。 對於Java ReentrantLock而言,經過構造函數指定該鎖是不是公平鎖,默認是非公平鎖。非公平鎖的優勢在於吞吐量比公平鎖大。
對於Synchronized而言,也是一種非公平鎖。因爲其並不像ReentrantLock是經過AQS的來實現線程調度,因此並無任何辦法使其變成公平鎖。
可重入鎖
可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。說的有點抽象,下面會有一個代碼的示例。 對於Java ReentrantLock而言, 他的名字就能夠看出是一個可重入鎖,其名字是ReentrantLock從新進入鎖。 對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可必定程度避免死鎖。
當子類重寫父類的synchronzied方法時,而後在子類中調用父類的方法
黃色部分當執行子類的doSomething()會獲取子類對象LoggingWidget的鎖,當執行 super.doSomething();時調用的父類的方法,而此時super只是告訴虛擬機去執行父類的doSomething()方法並無實例化父類
Widget,因此此時拿到的鎖仍是子類的LoggingWidget對象的鎖。一個線程獲取對象鎖的時,能夠再次獲取本對象鎖。
如何避免重入鎖:
將super改爲紅色部分,由程序自主實例化一個父類,這樣第二次拿到的鎖就是父類的Widget對象鎖,而不是兩次都得到是子類LoggingWidget的對象鎖
public class Widget {
public synchronized void doSomething(){
// do something
} }
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
super.doSomething();
}}
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
Widget widget = new Widget();
widget.doSomething();
}}
獨享鎖/共享鎖
獨享鎖是指該鎖一次只能被一個線程所持有。
共享鎖是指該鎖可被多個線程所持有。
對於Java ReentrantLock而言,其是獨享鎖。可是對於Lock的另外一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。 讀鎖的共享鎖可保證併發讀是很是高效的,讀寫,寫讀 ,寫寫的過程是互斥的。 獨享鎖與共享鎖也是經過AQS來實現的,經過實現不一樣的方法,來實現獨享或者共享。
對於Synchronized而言,固然是獨享鎖
互斥鎖/讀寫鎖
上面講的獨享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。
互斥鎖在Java中的具體實現就是ReentrantLock
讀寫鎖在Java中的具體實現就是ReadWriteLock
樂觀鎖/悲觀鎖
樂觀鎖與悲觀鎖不是指具體的什麼類型的鎖,而是指看待併發同步的角度。
悲觀鎖認爲對於同一個數據的併發操做,必定是會發生修改的,哪怕沒有修改,也會認爲修改。所以對於同一個數據的併發操做,悲觀鎖採起加鎖的形式。悲觀的認爲,不加鎖的併發操做必定會出問題。
樂觀鎖則認爲對於同一個數據的併發操做,是不會發生修改的。在更新數據的時候,會採用嘗試更新,不斷從新的方式更新數據。樂觀的認爲,不加鎖的併發操做是沒有事情的。
從上面的描述咱們能夠看出,悲觀鎖適合寫操做很是多的場景,樂觀鎖適合讀操做很是多的場景,不加鎖會帶來大量的性能提高。
悲觀鎖在Java中的使用,就是利用各類鎖。
樂觀鎖在Java中的使用,是無鎖編程,經常採用的是CAS算法,典型的例子就是原子類(AutomicInteger,AutomicLong,AutomicShort,AutomicReference<Object>),經過CAS自旋實現原子操做的更新。
分段鎖
分段鎖實際上是一種鎖的設計,並非具體的一種鎖,對於ConcurrentHashMap而言,其併發的實現就是經過分段鎖的形式來實現高效的併發操做。 咱們以ConcurrentHashMap來講一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱爲Segment,它即相似於HashMap(JDK7與JDK8中HashMap的實現)的結構,即內部擁有一個Entry數組,數組中的每一個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。 當須要put元素的時候,並非對整個hashmap進行加鎖,而是先經過hashcode來知道他要放在那一個分段中,而後對這個分段進行加鎖,因此當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。 可是,在統計size的時候,可就是獲取hashmap全局信息的時候,就須要獲取全部的分段鎖才能統計。 分段鎖的設計目的是細化鎖的粒度,當操做不須要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操做。
偏向鎖/輕量級鎖/重量級鎖(指的是同步鎖的狀態,針對synchronzied來講的)
無狀態鎖/偏向鎖/輕量級鎖/重量級鎖 這三種鎖是指鎖的狀態,而且是針對Synchronized。在Java 5經過引入鎖升級的機制來實現高效Synchronized。這三種鎖的狀態是經過對象監視器在對象頭中的字段來代表的。
偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。下降獲取鎖的代價。
爲了減小沒有競爭鎖的狀況下,當一個線程獲取同步鎖的時候,該同步鎖會自動偏向第一個線程,之後不須要在進行同步。
輕量級鎖是指當鎖是偏向鎖的時候,被另外一個線程所訪問,偏向鎖就會升級爲輕量級鎖,其餘線程會經過自旋的形式嘗試獲取鎖,不會阻塞,提升性能。
重量級鎖是指當鎖爲輕量級鎖的時候,另外一個線程雖然是自旋,但自旋不會一直持續下去,當自旋必定次數的時候,尚未獲取到鎖,就會進入阻塞,該鎖膨脹爲重量級鎖。重量級鎖會讓其餘申請的線程進入阻塞,性能下降。
這三種鎖會隨着競爭狀態的升級而升級,這能由低到高,不能降級。
自旋鎖
在Java中,自旋鎖是指嘗試獲取鎖的線程不會當即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減小線程狀態切換的消耗,缺點是循環會消耗CPU。