1. 程式人生 > 其它 >Java併發控制(synchronized、ReentrantLock、CountDownLatch)

Java併發控制(synchronized、ReentrantLock、CountDownLatch)

參考資料:

https://blog.csdn.net/zcl_love_wx/article/details/93977947

https://zhuanlan.zhihu.com/p/420560153

Java中鎖的實現方式有兩種:synchronized關鍵字和併發包中的鎖類。synchronized這個同步關鍵字以前效能不是太理想,在隨著不停的優化後,它已經成了同步的首選。

鎖涉及的幾個重要概念:重入鎖、自旋鎖、鎖偏向、鎖粗化、公平鎖與非公平鎖、輕量級鎖與重量級鎖、讀寫鎖與獨佔鎖(樂觀鎖與悲觀鎖)

synchronized、ReentrantLock 都屬於可重入鎖。

synchronized、ReentrantLock 都是悲觀鎖。

synchronized,ReentrantLock 都是獨佔鎖。

synchronized 是重量鎖。

synchronized 是非公平鎖,ReentrantLock可以通過建構函式指定該鎖是公平的還是非公平的,預設是非公平的。

問題1: 可重入鎖如果加了兩把,但是隻釋放了一把會出現什麼問題?

答:程式卡死,執行緒不能出來,也就是說我們申請了幾把鎖,就需要釋放幾把鎖。

問題2: 如果只加了一把鎖,釋放兩次會出現什麼問題?

答:會報錯,java.lang.IllegalMonitorStateException。

CountDownLatch 與 CyclicBarrier

CountDownLatch 它是一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。

CyclicBarrier 也是一個同步輔助類,它允許一組執行緒互相等待,直到到達某個公共屏障點 (common barrier point)。

類鎖和物件鎖(重要)

Class A {
     // ==>物件鎖:普通例項方法默認同步監視器就是this,
     // 即呼叫該方法的物件
     public synchronized methodA() {
     }

    public  methodB() {    
         // ==>物件鎖:this表示是物件鎖
         synchronized(this){ 
         }
     }

    // ==>類鎖:修飾靜態方法
     public static synchronized methodC() {
     }

    public methodD(){
         // ==>類鎖:A.class說明是類鎖
         synchronized(A.class){}
     }

    // 普通方法:任何情況下呼叫時,都不會發生競爭
     public common(){
     }
}

 

類鎖的5種形式

Class A {
     // 普通字串屬性
     private String val;
     // 靜態屬性
     private static Object staticObj;

     // ==>類鎖情況1:synchronized修飾靜態方法
     public static synchronized methodA() {
     }

    public methodB(){
         // ==>類鎖情況2:同步塊裡的物件是類
         synchronized(A.class){}
     }

     public methodC(){
          // ==>類鎖情況3:同步塊裡的物件是字串
         synchronized("ABC"){}
     }

    public methodD(){
         // ==>類鎖情況4:同步塊裡的物件是靜態屬性
         synchronized(staticObj){}
     }

    public methodE(){
         // ==>類鎖情況5:同步塊裡的物件是字串屬性
         synchronized(val){}
     }
}

鎖粗化也提醒了我們平時寫程式碼時,儘量不要在迴圈內使用鎖:

// 粗化前
for(int i=0;i<10000;i++){
     // 這會導致頻繁同步程式碼,無謂的消耗系統資源
     synchronized(monitor){
         doSomething...
     }
}
// 粗化後
synchronized(monitor){
     for(int i=0;i<10000;i++){   
         doSomething...
     }
}

 

鎖偏向

偏向鎖指的是,當第一個執行緒請求時,會判斷鎖的物件頭裡的ThreadId欄位的值,如果為空,則讓該執行緒持有偏向鎖,並將ThreadId的值置為當前執行緒ID。當前執行緒再次進入時,如果執行緒ID與ThreadId的值相等,則該執行緒就不會再重複獲取鎖了。因為鎖的請求與釋放是要消耗系統資源的。

如果有其他執行緒也來請求該鎖,則偏向鎖就會撤銷,然後升級為輕量級鎖。如果鎖的競爭十分激烈,則輕量級鎖又會升級為重量級鎖。