溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java并發編程之StampedLock鎖怎么應用

發布時間:2022-04-15 17:29:44 來源:億速云 閱讀:179 作者:zzz 欄目:開發技術

本篇內容介紹了“Java并發編程之StampedLock鎖怎么應用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

StampedLock:

StampedLock是并發包里面JDK8版本新增的一個鎖,該鎖提供了三種模式的讀寫控制,當調用獲取鎖的系列函數時,會返回一個long 型的變量,我們稱之為戳記(stamp),這個戳記代表了鎖的狀態。其中try 系列獲取鎖的函數,當獲取鎖失敗后會返回為0的stamp值。當調用釋放鎖和轉換鎖的方法時需要傳入獲取鎖時返回的stamp值。

StampedLock提供的三種讀寫模式的鎖分別如下:

  • 寫鎖witeLock: 是一個排它鎖或者獨占鎖,某時只有一個線程可以獲取該鎖,當一個線程獲取該鎖后,其他請求讀鎖和寫鎖的線程必須等待,這類似于 ReentrantReadWriteLock的寫鎖(不同的是這里的寫鎖是不可重入鎖):當目前沒有線程持有讀鎖或者寫鎖時才可以獲取到該鎖。請求該鎖成功后會返回一個stamp變量用來表示該鎖的版本,當釋放該鎖時需要調用unlockWrite方法并傳遞獲取鎖日的 stamp 參數。并且它提供了非阻塞的tryWriteLock 方法。

  • 悲觀讀鎖 readLock: 是一個共享鎖,在沒有線程獲取獨占寫鎖的情況下,多個線程可以同時獲取該鎖。如果已經有線程持有寫鎖,則其他線程請求獲取該讀鎖會被阻塞,這類似于 ReentrantReadWriteLock 的讀鎖(不同的是這里的讀鎖是不可重入鎖)。這里說的悲觀是指在具體操作數據前其會悲觀地認為其他線程可能要對自己操作的數據進行修改,所以需要先對數據加鎖,這是在讀少寫多的情況下的一種考慮。請求該鎖成功后會返回一個stamp變量用來表示該鎖的版本,當釋放該鎖時需要調用 unlockRead 方法并傳遞 stamp 參數。并且它提供了非阻塞的 tryReadLock 方法。

  • 樂觀讀鎖tryOptimisticRead: 它是相對于悲觀鎖來說的,在操作數據前并沒有通過 CAS設置鎖的狀態,僅僅通過位運算測試。如果當前沒有線程持有寫鎖,則簡單地返回一個非0的stamp版本信息。獲取該 stamp 后在具體操作數據前還需要調用 validate 方法驗證該 stamp 是否已經不可用,也就是看當調用 tryOptimisticRead 返回 stamp后到當前時間期間是否有其他線程持有了寫鎖,如果是則validate 會返回0否則就可以使用該stamp版本的鎖對數據進行操作。由于tryOptimisticRead 并沒有使用CAS設置鎖狀態,所以不需要顯式地釋放該鎖。該鎖的一個特點是適用于讀多寫少的場景,因為獲取讀鎖只是使用位操作進行檢驗,不涉及CAS操作,所以效率會高很多,但是同時由于沒有使用真正的鎖,在保證數據一致性上需要復制一份要操作的變量到方法棧,并且在操作數據時可能其他寫線程已經修改了數據,而我們操作的是方法棧里面的數據,也就是一個快照,所以最多返回的不是最新的數據,但是一致性還是得到保障的。

StampedLock還支持這三種鎖一定條件下進行相互轉換。例如long tryConvertToWriteLock(long stamp)期望把stamp 標示的鎖升級為寫鎖,

這個函數會在下面幾種情況下返回一個有效的stamp(也就是晉升寫鎖成功):

  • 當前鎖已經是寫鎖模式了。

  • 前鎖處于讀鎖模式,并且沒有其他線程是讀鎖模式

  • 當前處于樂觀讀模式,并且當前寫鎖可用

另外,StampedLock 的讀寫鎖都是不可重入鎖,所以在獲取鎖后釋放鎖前不應該再調用會獲取鎖的操作,以避免造成調用線程被阻塞。當多個線程同時嘗試獲取讀鎖和寫鎖時,誰先獲取鎖沒有一定的規則,完全都是盡力而為,是隨機的。并且該鎖不是直接實現 Lock 或 ReadWriteLock 接口,而是其在內部自己維護了一個雙向阻塞隊列。

下面通姑JDK8里面提供的一個管理二維點的例子來理解以上介紹的概念。

package LockSupportTest;

import com.sun.org.apache.bcel.internal.generic.BREAKPOINT;

import java.util.concurrent.locks.StampedLock;

public class Point_Class {
    private double x,y;
    private final StampedLock sl = new StampedLock();
    
    void move(double deltaX, double deltaY) {
        long stamp = sl.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            sl.unlockWrite(stamp);
        }
    }
    
    double distanceFromOrin() {
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX*currentX + currentY*currentY);
    }
    
    void moveIfAtOrigin(double newX, double newY) {
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
                    sl.unlock(stamp);
                }
            }
}

在如上代碼中,Point類里面有兩個成員變量(x,y)用來表示一個點的二維坐標,和三個操作坐標變量的方法。另外實例化了一個StampedLock對象用來保證操作的原子性。

“Java并發編程之StampedLock鎖怎么應用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女