Java8 讀寫鎖的改進:StampedLock(筆記)


     StampedLock是Java8引入的一種新的所機制,簡單的理解,可以認為它是讀寫鎖的一個改進版本,讀寫鎖雖然分離了讀和寫的功能,使得讀與讀之間可以完全並發,但是讀和寫之間依然是沖突的,讀鎖會完全阻塞寫鎖,它使用的依然是悲觀的鎖策略.如果有大量的讀線程,他也有可能引起寫線程的飢餓
     而StampedLock則提供了一種樂觀的讀策略,這種樂觀策略的鎖非常類似於無鎖的操作,使得樂觀鎖完全不會阻塞寫線程
  • StampedLock的使用實例
 
 
public class Point {
    private double x, y;//內部定義表示坐標點
    private final StampedLock s1 = new StampedLock();//定義了StampedLock鎖,

    void move(double deltaX, double deltaY) {
        long stamp = s1.writeLock();//這里的含義和distanceFormOrigin方法中 s1.readLock()是類似的
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            s1.unlockWrite(stamp);//退出臨界區,釋放寫鎖
        }
    }

    double distanceFormOrigin() {//只讀方法
        long stamp = s1.tryOptimisticRead();  //試圖嘗試一次樂觀讀 返回一個類似於時間戳的郵戳整數stamp 這個stamp就可以作為這一個所獲取的憑證
        double currentX = x, currentY = y;//讀取x和y的值,這時候我們並不確定x和y是否是一致的
        if (!s1.validate(stamp)) {//判斷這個stamp是否在讀過程發生期間被修改過,如果stamp沒有被修改過,責任無這次讀取時有效的,因此就可以直接return了,反之,如果stamp是不可用的,則意味着在讀取的過程中,可能被其他線程改寫了數據,因此,有可能出現臟讀,如果如果出現這種情況,我們可以像CAS操作那樣在一個死循環中一直使用樂觀鎖,知道成功為止
            stamp = s1.readLock();//也可以升級鎖的級別,這里我們升級樂觀鎖的級別,將樂觀鎖變為悲觀鎖, 如果當前對象正在被修改,則讀鎖的申請可能導致線程掛起.
            try {
                currentX = x;
                currentY = y;
            } finally {
                s1.unlockRead(stamp);//退出臨界區,釋放讀鎖
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
}

 

  • StampedLock的小陷阱
  • 有關StampedLock的實現思想
StampedLock的內部實現是基於CLH鎖的,CLH鎖是一種自旋鎖,它保證沒有飢餓的發生,並且可以保證FIFO(先進先出)的服務順序.
CLH鎖的基本思想如下:鎖維護一個等待線程隊列,所有申請鎖,但是沒有成功的線程都記錄在這個隊列中,每一個節點代表一個線程,保存一個標記位(locked).用與判斷當前線程是否已經釋放鎖;locked=true 沒有獲取到鎖,false 已經成功釋放了鎖
     當一個線程視圖獲得鎖時,取得等待隊列的尾部節點作為其前序節點.並使用類似如下代碼判斷前序節點是否已經成功釋放鎖:
while (pred.locked) {
   
}
     只要前序節點(pred)沒有釋放鎖,則表示當前線程還不能繼續執行,因此會自旋等待,
     反之,如果前序線程已經釋放鎖,則當前線程可以繼續執行.
     釋放鎖時,也遵循這個邏輯,線程會將自身節點的locked位置標記位false,那么后續等待的線程就能繼續執行了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM