1. 程式人生 > >JDK基礎--Java中的鎖概念

JDK基礎--Java中的鎖概念

Java中的鎖概念

掌握Java中鎖是Java多執行緒程式設計中繞不開的知識,只有知道理解Java各種鎖才能在編碼過程中靈活運用,寫出更高效的多執行緒程式。而理解掌握鎖的第一步,可從巨集觀上對比理解一下各種鎖概念。

在學習java的過程中會遇到各個各樣鎖的概念:公平鎖/非公平鎖、可重入鎖、單獨鎖/共享鎖、互斥鎖/讀寫鎖、樂觀鎖/悲觀鎖、分段鎖、偏向鎖/輕量級鎖/重量級鎖、自旋鎖、閉鎖、活鎖,當然最高名的鎖就是無鎖,也是高併發過程中的上層武功

在這些概念中,有的指鎖的狀態或型別, 有的指鎖的設計,在這裡整理並記錄一下:

一、公平鎖/非公平鎖

1.公平鎖是指按多個執行緒申請鎖的順序來獲取鎖。

2.非公平鎖是指多個執行緒獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的執行緒比先申請的執行緒優先獲取鎖。有可能,會造成優先順序反轉或者飢餓現象。

比如:對於Java ReentrantLock而言,通過建構函式指定該鎖是否是公平鎖,預設是非公平鎖。非公平鎖的優點在於吞吐量比公平鎖大。

對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS(AbstractQueuedSynchronized 抽象的佇列式的同步器 ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,FutureTask)的來實現執行緒排程,所以並沒有任何辦法使其變成公平鎖。

二、可重入鎖

可重入鎖又名遞迴鎖,是指在同一個執行緒在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖

ReentrantLock、Synchronized都是可重入鎖

synchronized void setA() throws Exception{
    Thread.sleep(1000);
    setB();
}

synchronized void setB() throws Exception{
    Thread.sleep(1000);
}

三、獨享鎖/共享鎖

1.獨享鎖是指該鎖一次只能被一個執行緒所持有。

2.共享鎖是指該鎖可被多個執行緒所持有。

對於ReentrantLock而言,其是獨享鎖。但是對於Lock的另一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。

讀鎖的共享鎖可保證併發讀是非常高效的,讀寫,寫讀 ,寫寫的過程是互斥的。

獨享鎖與共享鎖也是通過AQS來實現的,通過實現不同的方法,來實現獨享或者共享。

對於Synchronized而言,當然是獨享鎖。

四、互斥鎖/讀寫鎖

上面講的獨享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。互斥鎖在Java中的具體實現就是ReentrantLock

讀寫鎖在Java中的具體實現就是ReadWriteLock

五、樂觀鎖/悲觀鎖

不是具體型別的鎖,而是指看待併發同步的角度

悲觀鎖在Java中的使用,就是利用各種鎖。

樂觀鎖在Java中的使用,是無鎖程式設計,常常採用的是CAS演算法,典型的例子就是原子類,通過CAS自旋實現原子操作的更新。

六、分段鎖

分段鎖其實是一種鎖的設計,並不是具體的一種鎖,對於ConcurrentHashMap而言,其併發的實現就是通過分段鎖的形式來實現高效的併發操作,目的在於細化鎖粒度。

我們以ConcurrentHashMap來說一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱為Segment,它即類似於HashMap(JDK7與JDK8中HashMap的實現)的結構,即內部擁有一個Entry陣列,陣列中的每個元素又是一個連結串列;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。

七、偏向鎖、輕量級鎖、重量級鎖

這三種鎖是指鎖的狀態,並且是針對Synchronized。在Java 5通過引入鎖升級的機制來實現高效Synchronized。這三種鎖的狀態是通過物件監視器在物件頭中的欄位來表明的。

偏向鎖是指一段同步程式碼一直被一個執行緒所訪問,那麼該執行緒會自動獲取鎖。降低獲取鎖的代價。

輕量級鎖是指當鎖是偏向鎖的時候,被另一個執行緒所訪問,偏向鎖就會升級為輕量級鎖,其他執行緒會通過自旋的形式嘗試獲取鎖,不會阻塞,提高效能。

重量級鎖是指當鎖為輕量級鎖的時候,另一個執行緒雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的執行緒進入阻塞,效能降低。

八、自旋鎖

在Java中,自旋鎖是指嘗試獲取鎖的執行緒不會立即阻塞,而是採用迴圈的方式去嘗試獲取鎖,這樣的好處是減少執行緒上下文切換的消耗,缺點是迴圈會消耗CPU。

九、閉鎖

閉鎖是一種同步工具類,可以延遲執行緒的進度直到其到達終止狀態。閉鎖的作用相當於一扇門:在閉鎖到達結束狀態之前,這扇門一直是關閉的,並且沒有任何執行緒能通過,當到達結束狀態時,這扇門會開啟允許所有的執行緒通過。當閉鎖到達結束狀態後,將不會再改變狀態,因此這扇門將永遠保持開啟狀態。閉鎖可以用來確保某些活動指導其他活動都完成後才繼續執行。CountDownLatch就是一種靈活的閉鎖實現。

十、活鎖

LiveLock是一種形式活躍性問題,該問題儘管不會阻塞執行緒,但也不能繼續執行,因為執行緒將不斷重複執行相同的操作,而且總會失敗。活鎖通常傳送在處理事務訊息的應用程式中:如果不能成功地處理某個訊息,那麼訊息處理機制將回滾整個事務,並將它重新放到佇列的開頭:如果不能成功地處理某個訊息,那麼訊息處理機制將回滾整個事務,並將它重新放到佇列的開頭。如果訊息處理器在處理某種特定型別的訊息時存在錯誤並導致它失敗,那麼每當這個訊息從佇列中取出並傳遞到存在錯誤的處理器時,都會發生事務回滾。由於這條訊息又被放回到佇列開頭,因此處理器將被反覆呼叫,並返回相同的結果。

十一、無鎖

要保證現場安全,並不是一定就要進行同步,兩者沒有因果關係。同步只是保證共享資料爭用時的正確性的手段,如果一個方法本來就不涉及共享資料,那它自然就無須任何同步措施去保證正確性,因此會有一些程式碼天生就是執行緒安全的。

無狀態程式設計。無狀態程式碼有一些共同的特徵:不依賴於儲存在對上的資料和公用的系統資源、用到的狀態量都由引數中傳入、不呼叫非無狀態的方法等。可以參考Servlet。

執行緒本地儲存。可以參考ThreadLocal

volatile

CAS

協程:在單執行緒裡實現多工的排程,並在單執行緒裡維持多個任務