<bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>
    Fork me on GitHub

    騰訊面試:什么鎖比讀寫鎖性能更高?

    在并發編程中,讀寫鎖 ReentrantReadWriteLock 的性能已經算是比較高的了,因為它將悲觀鎖的粒度分的更細,在它里面有讀鎖和寫鎖,當所有操作為讀操作時,并發線程是可以共享讀鎖同時運行的,這樣就無需排隊執行了,所以執行效率也就更高。

    那么問題來了,有沒有比讀寫鎖 ReentrantReadWriteLock 性能更高的鎖呢?

    答案是有的,在 Java 中,比 ReentrantReadWriteLock 性能更高的鎖有以下兩種:

    1. 樂觀鎖:樂觀鎖是一種非阻塞鎖機制,它是通過 Compare-And-Swap(CAS)對比并替換來進行數據的更改的,它假設多個線程(或進程)之間很少會發生沖突,因此不會加鎖,只有在需要修改之后,通過對比并替換來修改共享變量的值,因此它在非高并發的環境下的性能是非常高的。
    2. StampedLock:它是 JDK 8 中新增的鎖類型,它提供了三種鎖模式:讀鎖、寫鎖和樂觀讀鎖。相較于 ReentrantReadWriteLock,StampedLock 提供了更細粒度的控制,支持樂觀讀取操作,可以提高并發性能。

    1.樂觀鎖

    樂觀鎖在 Java 中最常見的實現就是 atomic 家族下的類,例如 AtomicInteger、AtomicLong 等,它的核心方法中使用了 CAS 對比并替換進行變量的修改操作,如下源碼所示:

    public final int incrementAndGet() {
        return U.getAndAddInt(this, VALUE, 1) + 1;
    }
    public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!weakCompareAndSetInt(o, offset, v, v + delta)); // CAS 方法
        return v;
    }
    

    然而,如果是高并發環境下,那么樂觀鎖可以需要通過多次自旋才能成功修改變量的數據,這種場景下,樂觀鎖的性能可能就不如 ReentrantReadWriteLock 了。

    2.StampedLock

    StampedLock 有三種讀寫方法:

    • readLock:讀鎖,用于多線程并發讀取共享資源。
    • writeLock:寫鎖,用于獨占寫入共享資源。
    • tryOptimisticRead:讀樂觀鎖,用于在不阻塞其他線程的情況下嘗試讀取共享資源。

    其中 readLock() 和 writeLock() 方法與 ReentrantReadWriteLock 的用法類似,而 tryOptimisticRead() 方法則是 StampedLock 引入的新方法,它用于非常短的讀操作。

    因此,我們在加鎖時,可以使用性能更高的讀樂觀鎖來替代傳統的讀鎖,如果能加鎖成功,則它可以和其他線程(即使是寫操作)一起執行,也無需排隊運行(傳統讀鎖遇到寫鎖時需要排隊執行),這樣的話 StampedLock 的執行效率就會更高,它是使用如下:

    // 創建 StampedLock 實例
    StampedLock lock = new StampedLock();
    // 獲取樂觀讀鎖
    long stamp = lock.tryOptimisticRead(); 
    // 讀取共享變量
    if (!lock.validate(stamp)) { // 檢查樂觀讀鎖是否有效
        stamp = lock.readLock(); // 如果樂觀讀鎖無效,則獲取悲觀讀鎖
        try {
            // 重新讀取共享變量
        } finally {
            lock.unlockRead(stamp); // 釋放悲觀讀鎖
        }
    }
    
    // 獲取悲觀讀鎖
    long stamp = lock.readLock(); 
    try {
        // 讀取共享變量
    } finally {
        lock.unlockRead(stamp); // 釋放悲觀讀鎖
    }
    
    // 獲取寫鎖
    long stamp = lock.writeLock(); 
    try {
        // 寫入共享變量
    } finally {
        lock.unlockWrite(stamp); // 釋放寫鎖
    }
    

    使用樂觀讀鎖的特性可以提高讀操作的并發性能,適用于讀多寫少的場景。如果樂觀讀鎖獲取后,在讀取共享變量前發生了寫入操作,則 validate 方法會返回 false,此時需要轉換為悲觀讀鎖或寫鎖重新訪問共享變量。

    課后思考

    StampedLock 底層是如何實現的?

    本文已收錄到我的面試小站 www.javacn.site,其中包含的內容有:Redis、JVM、并發、并發、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、消息隊列等模塊。

    posted @ 2024-05-15 09:38  磊哥|www.javacn.site  閱讀(51)  評論(0編輯  收藏  舉報
    免费视频精品一区二区_日韩一区二区三区精品_aaa在线观看免费完整版_世界一级真人片
    <bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>