亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java并發(fā)編程ReentrantReadWriteLock加讀鎖流程

 更新時(shí)間:2023年05月10日 11:10:42   作者:bright丶  
這篇文章主要介紹了Java并發(fā)編程ReentrantReadWriteLock加讀鎖流程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    int r = sharedCount(c);
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
        compareAndSetState(c, c + SHARED_UNIT)) {
        if (r == 0) {
            firstReader = current;
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {
            firstReaderHoldCount++;
        } else {
            HoldCounter rh = cachedHoldCounter;
            if (rh == null || rh.tid != getThreadId(current))
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    return fullTryAcquireShared(current);
}

上面是嘗試加讀鎖流程的代碼,既然這篇是番外篇,那就不按正常流程一點(diǎn)一點(diǎn)去分析了,著重拿出一部分來分析一下。ReentrantReadWriteLockReentrantLock相比,除了多了讀寫鎖之外,還增加了很多屬性,比如firstReader、firstReaderHoldCount、cachedHoldCounter......那我們這篇文章就介紹一下這些新屬性的含義以及上面代碼中加鎖成功后的處理。

屬性介紹

static final class HoldCounter {
    int count = 0;
    final long tid = getThreadId(Thread.currentThread());
}

HoldCount類型用來存儲線程ID和線程持有的讀鎖數(shù)量

private transient ThreadLocalHoldCounter readHolds;
static final class ThreadLocalHoldCounter
    extends ThreadLocal&lt;HoldCounter&gt; {
    public HoldCounter initialValue() {
        return new HoldCounter();
    }
}

readHolds通過ThreadLocal在線程本地存儲了一個(gè)HoldCounter對象,表示當(dāng)前線程持有的讀鎖重入數(shù)量,主要是為了方便在發(fā)生重入或者釋放鎖時(shí),分別計(jì)算每個(gè)線程持有的讀鎖數(shù)量。

private transient HoldCounter cachedHoldCounter;

cachedHoldCounter存儲的是最后一個(gè)獲取讀鎖成功的線程持有的讀鎖數(shù)量。但是如果只有一個(gè)線程獲取讀鎖,會使用firstReaderfirstReaderHoldCount來記錄線程持有讀鎖數(shù)量,只有獲取讀鎖的線程數(shù)大于1時(shí)才會用cachedHoldCounter存儲最后線程持有的讀鎖數(shù)量。

private transient Thread firstReader = null;

第一個(gè)獲取讀鎖的線程,確切地說是把讀鎖數(shù)量從0改成1的線程,并且當(dāng)前還沒有釋放鎖。如果第一個(gè)線程釋放了鎖,就會把firstReader設(shè)為null,只有當(dāng)所有讀鎖釋放之后,下一個(gè)獲取讀鎖成功的線程就成為firstReader。

private transient int firstReaderHoldCount;

第一個(gè)獲取讀鎖的線程持有讀鎖的數(shù)量。

加鎖成功處理

int r = sharedCount(c);
if (r == 0) {
    firstReader = current;
    firstReaderHoldCount = 1;
} else if (firstReader == current) {
    firstReaderHoldCount++;
} else {
    HoldCounter rh = cachedHoldCounter;
    if (rh == null || rh.tid != getThreadId(current))
        cachedHoldCounter = rh = readHolds.get();
    else if (rh.count == 0)
        readHolds.set(rh);
    rh.count++;
}

這里截取加鎖成功之后處理的代碼來分析下對這些屬性的操作。

  • if (r == 0)表示共享鎖數(shù)量為0,當(dāng)前線程就是第一個(gè)獲取讀鎖成功的線程,所以firstReaderfirstReaderHoldCount記錄的就是當(dāng)前線程。
  • 如果讀鎖數(shù)量不是0,但是當(dāng)前線程是第一個(gè)線程,那就直接在原來數(shù)量基礎(chǔ)上進(jìn)行累加 firstReaderHoldCount++;
  • 如果讀鎖數(shù)量不為0,而且當(dāng)前線程也不是第一個(gè)線程,這時(shí)就需要用到cachedHoldCounter了。
    • rh == null表示當(dāng)前線程是第二個(gè)線程,rh.tid != getThreadId(current)表示當(dāng)前線程至少是第三個(gè)線程(這里不考慮重入情況,只考慮當(dāng)前線程第一次獲取讀鎖成功),兩個(gè)條件合起來可以理解為之前緩存的最后一個(gè)獲取讀鎖成功的線程不是當(dāng)前線程,所以就需要更新為當(dāng)前線程cachedHoldCounter = rh = readHolds.get()。
    • 如果之前緩存的最后一個(gè)線程是當(dāng)前線程,那么就會有一個(gè)特殊情況rh.count == 0,這里可以理解為一個(gè)線程釋放了讀鎖之后又重新獲取了讀鎖,釋放完所有鎖時(shí),為了防止內(nèi)存泄漏會調(diào)用readHolds.remove()清除線程本地存儲的信息,而現(xiàn)在加鎖成功了就需要在線程本地重新記錄持有鎖的數(shù)量,既然緩存的就是當(dāng)前線程的,那就直接用緩存來更新到線程本地就可以了。

以上就是Java并發(fā)編程ReentrantReadWriteLock番外的詳細(xì)內(nèi)容,更多關(guān)于Java并發(fā)ReentrantReadWriteLock的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot日志配置簡單介紹

    SpringBoot日志配置簡單介紹

    這篇文章主要介紹了SpringBoot日志配置,需要的朋友可以參考下
    2017-09-09
  • 利用Java編寫一個(gè)屬于自己的日歷

    利用Java編寫一個(gè)屬于自己的日歷

    這篇文章主要為大家介紹了如何利用Java編寫一個(gè)屬于自己的日歷,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起嘗試一下
    2022-05-05
  • Spring Bean生命周期源碼原理圖解

    Spring Bean生命周期源碼原理圖解

    這篇文章主要介紹了Spring Bean生命周期源碼原理圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Mybatis/Mybatis-Plus駝峰式命名映射的實(shí)現(xiàn)

    Mybatis/Mybatis-Plus駝峰式命名映射的實(shí)現(xiàn)

    本文主要介紹了Mybatis-Plus駝峰式命名映射的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Java平臺調(diào)試體系原理分析和實(shí)踐整理 遠(yuǎn)程Debug

    Java平臺調(diào)試體系原理分析和實(shí)踐整理 遠(yuǎn)程Debug

    這篇文章主要介紹了Java平臺調(diào)試體系原理分析和實(shí)踐整理 遠(yuǎn)程Debug,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 新手了解java 類,對象以及封裝基礎(chǔ)知識

    新手了解java 類,對象以及封裝基礎(chǔ)知識

    JS是一門面向?qū)ο笳Z言,其對象是用prototype屬性來模擬的,本文介紹了如何封裝JS對象,具有一定的參考價(jià)值,下面跟著小編一起來看下吧,希望對你有所幫助
    2021-07-07
  • 解決Error:(1,?1)?java:?非法字符:?'\ufeff'問題

    解決Error:(1,?1)?java:?非法字符:?'\ufeff'問題

    這篇文章主要介紹了解決Error:(1,?1)?java:?非法字符:?'\ufeff'問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Maven中Junit測試@Test等注解無法識別的問題及解決

    Maven中Junit測試@Test等注解無法識別的問題及解決

    這篇文章主要介紹了Maven中Junit測試@Test等注解無法識別的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java泛型的使用限制實(shí)例分析

    Java泛型的使用限制實(shí)例分析

    這篇文章主要介紹了Java泛型的使用限制,結(jié)合實(shí)例形式分析了不能使用java泛型的情況以及泛型使用的相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2019-08-08
  • Java FastJson使用教程

    Java FastJson使用教程

    這篇文章主要介紹了如何使用FastJson,幫助大家將 Java 對象轉(zhuǎn)換為 JSON 格式,感興趣的朋友可以了解下
    2020-10-10

最新評論