最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java利用StampedLock實(shí)現(xiàn)讀寫鎖的方法詳解

 更新時(shí)間:2022年10月18日 08:59:30   作者:JAVA旭陽  
在jdk8以后,java提供了一個(gè)性能更優(yōu)越的讀寫鎖并發(fā)類StampedLock,該類的設(shè)計(jì)初衷是作為一個(gè)內(nèi)部工具類,用于輔助開發(fā)其它線程安全組件。本文就來和大家一起學(xué)習(xí)下StampedLock的功能和使用

概述

想到讀寫鎖,大家第一時(shí)間想到的可能是ReentrantReadWriteLock。實(shí)際上,在jdk8以后,java提供了一個(gè)性能更優(yōu)越的讀寫鎖并發(fā)類StampedLock,該類的設(shè)計(jì)初衷是作為一個(gè)內(nèi)部工具類,用于輔助開發(fā)其它線程安全組件,用得好,該類可以提升系統(tǒng)性能,用不好,容易產(chǎn)生死鎖和其它莫名其妙的問題。本文主要和大家一起學(xué)習(xí)下StampedLock的功能和使用。

StampedLock介紹

StampedLock的狀態(tài)由版本和模式組成。鎖獲取方法返回一個(gè)戳,該戳表示并控制對(duì)鎖狀態(tài)的訪問。StampedLock提供了3種模式控制訪問鎖:

1.寫模式

獲取寫鎖,它是獨(dú)占的,當(dāng)鎖處于寫模式時(shí),無法獲得讀鎖,所有樂觀讀驗(yàn)證都將失敗。

  • writeLock(): 阻塞等待獨(dú)占獲取鎖,返回一個(gè)戳, 如果是0表示獲取失敗。
  • tryWriteLock():嘗試獲取一個(gè)寫鎖,返回一個(gè)戳, 如果是0表示獲取失敗。
  • long tryWriteLock(long time, TimeUnit unit): 嘗試獲取一個(gè)獨(dú)占寫鎖,可以等待一段事件,返回一個(gè)戳, 如果是0表示獲取失敗。
  • long writeLockInterruptibly(): 試獲取一個(gè)獨(dú)占寫鎖,可以被中斷,返回一個(gè)戳, 如果是0表示獲取失敗。
  • unlockWrite(long stamp):釋放獨(dú)占寫鎖,傳入之前獲取的戳。
  • tryUnlockWrite():如果持有寫鎖,則釋放該鎖,而不需要戳值。這種方法可能對(duì)錯(cuò)誤后的恢復(fù)很有用。
long stamp = lock.writeLock();
try {
    ....
} finally {
    lock.unlockWrite(stamp);
}

2.讀模式

悲觀的方式后去非獨(dú)占讀鎖。

  • readLock(): 阻塞等待獲取非獨(dú)占的讀鎖,返回一個(gè)戳, 如果是0表示獲取失敗。
  • tryReadLock():嘗試獲取一個(gè)讀鎖,返回一個(gè)戳, 如果是0表示獲取失敗。
  • long tryReadLock(long time, TimeUnit unit): 嘗試獲取一個(gè)讀鎖,可以等待一段事件,返回一個(gè)戳, 如果是0表示獲取失敗。
  • long readLockInterruptibly(): 阻塞等待獲取非獨(dú)占的讀鎖,可以被中斷,返回一個(gè)戳, 如果是0表示獲取失敗。
  • unlockRead(long stamp):釋放非獨(dú)占的讀鎖,傳入之前獲取的戳。
  • tryUnlockRead():如果讀鎖被持有,則釋放一次持有,而不需要戳值。這種方法可能對(duì)錯(cuò)誤后的恢復(fù)很有用。
long stamp = lock.readLock();
try {
    ....
} finally {
    lock.unlockRead(stamp);	    
}

3.樂觀讀模式

樂觀讀也就是若讀的操作很多,寫的操作很少的情況下,你可以樂觀地認(rèn)為,寫入與讀取同時(shí)發(fā)生幾率很少,因此不悲觀地使用完全的讀取鎖定,程序可以查看讀取資料之后,是否遭到寫入執(zhí)行的變更,再采取后續(xù)的措施(重新讀取變更信息,或者拋出異常) ,這一個(gè)小小改進(jìn),可大幅度提高程序的吞吐量。

StampedLock 支持 tryOptimisticRead() 方法,讀取完畢后做一次戳校驗(yàn),如果校驗(yàn)通過,表示這期間沒有其他線程的寫操作,數(shù)據(jù)可以安全使用,如果校驗(yàn)沒通過,需要重新獲取讀鎖,保證數(shù)據(jù)一致性。

  • tryOptimisticRead(): 返回稍后可以驗(yàn)證的戳記,如果獨(dú)占鎖定則返回零。
  • boolean validate(long stamp): 如果自給定戳記發(fā)行以來鎖還沒有被獨(dú)占獲取,則返回true。
long stamp = lock.tryOptimisticRead();
// 驗(yàn)戳
if(!lock.validate(stamp)){
	// 鎖升級(jí)
}

此外,StampedLock 提供了api實(shí)現(xiàn)上面3種方式進(jìn)行轉(zhuǎn)換:

long tryConvertToWriteLock(long stamp)

如果鎖狀態(tài)與給定的戳記匹配,則執(zhí)行以下操作之一。如果戳記表示持有寫鎖,則返回它?;蛘?,如果是讀鎖,如果寫鎖可用,則釋放讀鎖并返回寫戳記?;蛘撸绻菢酚^讀,則僅在立即可用時(shí)返回寫戳記。該方法在所有其他情況下返回零

long tryConvertToReadLock(long stamp)

如果鎖狀態(tài)與給定的戳記匹配,則執(zhí)行以下操作之一。如果戳記表示持有寫鎖,則釋放它并獲得讀鎖?;蛘?,如果是讀鎖,返回它。或者,如果是樂觀讀,則僅在立即可用時(shí)才獲得讀鎖并返回讀戳記。該方法在所有其他情況下返回零。

long tryConvertToOptimisticRead(long stamp)

如果鎖狀態(tài)與給定的戳記匹配,那么如果戳記表示持有鎖,則釋放它并返回一個(gè)觀察戳記?;蛘?,如果是樂觀讀,則在驗(yàn)證后返回它。該方法在所有其他情況下返回0,因此作為“tryUnlock”的形式可能很有用。

演示例子

下面用一個(gè)例子演示下StampedLock的使用,例子來源jdk中的javadoc。

@Slf4j
@Data
public class Point {
    private double x, y;
    private final StampedLock sl = new StampedLock();

    void move(double deltaX, double deltaY) throws InterruptedException {
        //涉及對(duì)共享資源的修改,使用寫鎖-獨(dú)占操作
        long stamp = sl.writeLock();
        log.info("writeLock lock success");
        Thread.sleep(500);
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            sl.unlockWrite(stamp);
            log.info("unlock write lock success");
        }
    }

    /**
     * 使用樂觀讀鎖訪問共享資源
     * 注意:樂觀讀鎖在保證數(shù)據(jù)一致性上需要拷貝一份要操作的變量到方法棧,并且在操作數(shù)據(jù)時(shí)候可能其他寫線程已經(jīng)修改了數(shù)據(jù),
     * 而我們操作的是方法棧里面的數(shù)據(jù),也就是一個(gè)快照,所以最多返回的不是最新的數(shù)據(jù),但是一致性還是得到保障的。
     *
     * @return
     */
    double distanceFromOrigin() throws InterruptedException {
        long stamp = sl.tryOptimisticRead();    // 使用樂觀讀鎖
        log.info("tryOptimisticRead lock success");
        // 睡一秒中
        Thread.sleep(1000);
        double currentX = x, currentY = y;      // 拷貝共享資源到本地方法棧中
        if (!sl.validate(stamp)) {              // 如果有寫鎖被占用,可能造成數(shù)據(jù)不一致,所以要切換到普通讀鎖模式
            log.info("validate stamp error");
            stamp = sl.readLock();
            log.info("readLock success");
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
                log.info("unlock read success");
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

    void moveIfAtOrigin(double newX, double newY) { // upgrade
        // Could instead start with optimistic, not read mode
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);  //讀鎖轉(zhuǎn)換為寫鎖
                if (ws != 0L) {
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
            sl.unlock(stamp);
        }
    }
}

測(cè)試用例:

@Test
public void testStamped() throws InterruptedException {
    Point point = new Point();
    point.setX(1);
    point.setY(2);
    // 線程0 執(zhí)行了樂觀讀
    Thread thread0 = new Thread(() -> {
        try {
            // 樂觀讀
            point.distanceFromOrigin();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "thread-0");
    thread0.start();

    Thread.sleep(500);
    // 線程1 執(zhí)行寫鎖
    Thread thread1 = new Thread(() -> {
        // 樂觀讀
        try {
            point.move(3, 4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "thread-1");
    thread1.start();

    thread0.join();
    thread1.join();
}

結(jié)果:

性能對(duì)比

正是由于StampedLock的樂觀讀模式,早就StampedLock的高性能和高吞吐量,那么具體的性能提高有多少呢?

下圖是和ReadWritLock相比,在一個(gè)線程情況下,讀速度是其4倍左右,寫是1倍。

下圖是16個(gè)線程情況下,讀性能是其幾十倍,寫性能也是近10倍左右:

下圖是吞吐量提高:

那么這樣是不是說StampedLock可以全方位的替代ReentrantReadWriteLock, 答案是否定的,StampedLock相對(duì)于ReentrantReadWriteLock有下面兩個(gè)問題:

  • 不支持條件變量Condition
  • 不支持可重入

所以最終選擇StampedLock還是ReentrantReadWriteLock,還是要看具體的業(yè)務(wù)場(chǎng)景。

總結(jié)

本文主要講解了StampedLock的功能和使用,至于原理,StampedLock雖然不像其它鎖一樣定義了內(nèi)部類來實(shí)現(xiàn)AQS框架,但是StampedLock的基本實(shí)現(xiàn)思路還是利用CLH隊(duì)列進(jìn)行線程的管理,通過同步狀態(tài)值來表示鎖的狀態(tài)和類型,具體的源碼實(shí)現(xiàn)大家感興趣的自己可以追蹤看看。

以上就是Java利用StampedLock實(shí)現(xiàn)讀寫鎖的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Java StampedLock讀寫鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 通過實(shí)例解析Spring Ioc項(xiàng)目實(shí)現(xiàn)過程

    通過實(shí)例解析Spring Ioc項(xiàng)目實(shí)現(xiàn)過程

    這篇文章主要介紹了Spring Ioc項(xiàng)目實(shí)踐過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java關(guān)于含有繼承類的成員初始化過程講解

    Java關(guān)于含有繼承類的成員初始化過程講解

    今天小編就為大家分享一篇Java關(guān)于含有繼承類的成員初始化過程講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • IDEA2022創(chuàng)建SpringBoot項(xiàng)目的圖文教程

    IDEA2022創(chuàng)建SpringBoot項(xiàng)目的圖文教程

    本文主要介紹了IDEA2022創(chuàng)建SpringBoot項(xiàng)目的圖文教程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Java中異常Exception和捕獲以及自定義異常詳解

    Java中異常Exception和捕獲以及自定義異常詳解

    在工作過程中,我們常常需要在合適的地方拋出合適的異常,除了java自帶的一些異常,我們可以在項(xiàng)目中定制自己的異常,并且全局捕獲它,下面這篇文章主要給大家介紹了關(guān)于Java中異常Exception和捕獲以及自定義異常的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Spring?Security過濾器鏈加載執(zhí)行流程源碼解析

    Spring?Security過濾器鏈加載執(zhí)行流程源碼解析

    Spring?Boot?對(duì)于?Spring?Security?提供了自動(dòng)化配置方案,可以使用更少的配置來使用?Spring?Security。那么這個(gè)過濾器鏈?zhǔn)窃趺醇虞d和實(shí)現(xiàn)攔截的呢,對(duì)Spring?Security過濾器鏈加載執(zhí)行流程感興趣的朋友一起看看吧
    2021-12-12
  • Java線程池的應(yīng)用實(shí)例分析

    Java線程池的應(yīng)用實(shí)例分析

    這篇文章主要介紹了Java線程池的應(yīng)用,結(jié)合具體實(shí)例形式分析了java線程池的斐波那契數(shù)列計(jì)算與模擬工人做工等應(yīng)用的操作技巧,需要的朋友可以參考下
    2019-10-10
  • Java多線程之Future設(shè)計(jì)模式

    Java多線程之Future設(shè)計(jì)模式

    這篇文章主要介紹了Java多線程之Future設(shè)計(jì)模式,F(xiàn)uture 代表的是未來的一個(gè)憑據(jù),文章主要附上Future具體實(shí)現(xiàn)類、橋接Future和FutureTask的代碼,需要的朋友可以參考一下
    2021-10-10
  • Java枚舉詳解及使用實(shí)例(涵蓋了所有典型用法)

    Java枚舉詳解及使用實(shí)例(涵蓋了所有典型用法)

    這篇文章主要介紹了Java枚舉詳解及使用實(shí)例(涵蓋了所有典型用法),本文直接給出實(shí)例代碼,代碼中包含詳細(xì)注釋,需要的朋友可以參考下
    2015-05-05
  • java 遍歷Map的幾種方法總結(jié)

    java 遍歷Map的幾種方法總結(jié)

    這篇文章主要介紹了java 遍歷Map的四種方法,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-10-10
  • java  HttpServletRequest和HttpServletResponse詳解

    java HttpServletRequest和HttpServletResponse詳解

    這篇文章主要介紹了java HttpServletRequest和HttpServletResponse詳解的相關(guān)資料,需要的朋友可以參考下
    2016-12-12

最新評(píng)論

沅陵县| 探索| 潮安县| 许昌县| 河西区| 伊川县| 密山市| 芮城县| 冕宁县| 新河县| 阿勒泰市| 定南县| 邵武市| 黄陵县| 大足县| 城固县| 旬阳县| 方城县| 凭祥市| 海阳市| 成都市| 奇台县| 江门市| 大田县| 东明县| 北海市| 关岭| 玉山县| 温州市| 大名县| 探索| 临夏县| 萨嘎县| 松桃| 尉犁县| 石河子市| 桐乡市| 道孚县| 准格尔旗| 宜春市| 石门县|