1. 程式人生 > 實用技巧 >python異常的處理

python異常的處理

技術標籤:java高併發lockjuc

ReentrantReadWriteLock讀寫鎖的使用

ReentrantReadWriteLock是juc下的一個併發讀寫鎖。它可以進行精確的讀寫鎖控制,通常用於讀多寫少的場景。

特點

通過readLock()方法和writeLock()獲取響應的讀鎖和寫鎖。讀鎖其他執行緒可以共同進入,不會對讀鎖進行互斥。寫鎖只有在讀鎖釋放後才能請求上鎖。寫鎖上鎖後讀鎖還能繼續上鎖。適合更新資料時讀操作一起停止的場景。

例項

ReentrantReadWriteLock寫法

import java.util.HashMap;
import java.util.
Map; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author AJ * @date 2021 2021-01-10 11:21 */ public class ReadWriteLock { public static volatile Map<String,String> map=new HashMap(); public static void main(String[] args) { // map.put("k1","value");
String value=""; ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(); //獲取讀寫鎖 ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock(); ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock
(); //加讀鎖 readLock.lock(); if(map.get("k1") == null){ System.out.println("k1 為空"); readLock.unlock(); //不釋放讀鎖,會導致寫鎖無法上鎖 writeLock.lock(); try{ if(map.get("k1") == null){ //dcl,雙重檢查,防止上鎖途中其他執行緒已經插入資料 map.put("k1","value"); } readLock.lock(); //鎖降級,防止資料被其他執行緒篡改,導致髒讀 }finally { writeLock.unlock(); } } try{ System.out.println(map.get("k1")); //鎖降級程式碼中獲取資料,由於讀鎖已經獲取到,其他執行緒無法獲取到寫鎖了。保證資料為該執行緒設定的資料 }finally { readLock.unlock(); } } }

該例子展示了一個簡單的讀寫互斥的場景。在正常情況下map有值時,多執行緒讀取不會受到影響。只有當map為空時,執行緒上寫鎖,此時所有的讀鎖和寫鎖都"暫停",等待寫鎖釋放(包括讀操作也會暫停!!!)。在寫鎖裡面可以進行讀鎖上鎖(鎖降級),避免寫鎖釋放讀鎖上鎖的間隙時間被其他執行緒上寫鎖更新資料導致本執行緒讀取到的資料和更新的資料不一致(髒資料)。

synchronized寫法

public static void sync(){
       System.out.println(map.get("k1"));  //②
       if(map.get("k1") == null){
            synchronized (ReadWriteLock.class){
                if(map.get("k1") == null){   //dcl判斷
                    map.put("k1","value");
                }

            }
        }
      System.out.println(map.get("k1"));  //②
    }

synchronized的寫法更為簡單粗暴,可以直接對所有的讀寫操作都加鎖後再進行查詢,但是鎖的粒度比較大,讀操作也無法進行併發。或者像操作②一樣,將讀操作放在鎖外面,但此時讀操作無法控制,程式進行寫操作的時候其他程式依舊可以進行讀操作。

總結

需要在進行寫入時控制讀操作時可以使用ReentrantReadWriteLock,達到更精細的控制粒度,這個是synchronized無法做到的。實際應用場景方面,ReentrantReadWriteLock可以用在雙重單例模式中的第一個判空。