Java并發(fā)編程ReentrantReadWriteLock加讀鎖流程
正文
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)去分析了,著重拿出一部分來分析一下。ReentrantReadWriteLock和ReentrantLock相比,除了多了讀寫鎖之外,還增加了很多屬性,比如firstReader、firstReaderHoldCount、cachedHoldCounter......那我們這篇文章就介紹一下這些新屬性的含義以及上面代碼中加鎖成功后的處理。
屬性介紹
static final class HoldCounter {
int count = 0;
final long tid = getThreadId(Thread.currentThread());
}
HoldCount類型用來存儲(chǔ)線程ID和線程持有的讀鎖數(shù)量
private transient ThreadLocalHoldCounter readHolds;
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
readHolds通過ThreadLocal在線程本地存儲(chǔ)了一個(gè)HoldCounter對象,表示當(dāng)前線程持有的讀鎖重入數(shù)量,主要是為了方便在發(fā)生重入或者釋放鎖時(shí),分別計(jì)算每個(gè)線程持有的讀鎖數(shù)量。
private transient HoldCounter cachedHoldCounter;
cachedHoldCounter存儲(chǔ)的是最后一個(gè)獲取讀鎖成功的線程持有的讀鎖數(shù)量。但是如果只有一個(gè)線程獲取讀鎖,會(huì)使用firstReader和firstReaderHoldCount來記錄線程持有讀鎖數(shù)量,只有獲取讀鎖的線程數(shù)大于1時(shí)才會(huì)用cachedHoldCounter存儲(chǔ)最后線程持有的讀鎖數(shù)量。
private transient Thread firstReader = null;
第一個(gè)獲取讀鎖的線程,確切地說是把讀鎖數(shù)量從0改成1的線程,并且當(dāng)前還沒有釋放鎖。如果第一個(gè)線程釋放了鎖,就會(huì)把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è)獲取讀鎖成功的線程,所以firstReader和firstReaderHoldCount記錄的就是當(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)前線程,那么就會(huì)有一個(gè)特殊情況
rh.count == 0,這里可以理解為一個(gè)線程釋放了讀鎖之后又重新獲取了讀鎖,釋放完所有鎖時(shí),為了防止內(nèi)存泄漏會(huì)調(diào)用readHolds.remove()清除線程本地存儲(chǔ)的信息,而現(xiàn)在加鎖成功了就需要在線程本地重新記錄持有鎖的數(shù)量,既然緩存的就是當(dāng)前線程的,那就直接用緩存來更新到線程本地就可以了。
以上就是Java并發(fā)編程ReentrantReadWriteLock番外的詳細(xì)內(nèi)容,更多關(guān)于Java并發(fā)ReentrantReadWriteLock的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Java的文件與目錄管理以及輸入輸出相關(guān)操作
這篇文章主要介紹了詳解Java的文件與目錄管理以及輸入輸出相關(guān)操作,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
使用多個(gè)servlet時(shí)Spring security需要指明路由匹配策略問題
這篇文章主要介紹了使用多個(gè)servlet時(shí)Spring security需要指明路由匹配策略問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Java實(shí)現(xiàn)向數(shù)組里添加元素
這篇文章主要介紹了Java實(shí)現(xiàn)向數(shù)組里添加元素方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
淺談idea中導(dǎo)入maven項(xiàng)目的兩種方式
本文主要介紹了淺談idea中導(dǎo)入maven項(xiàng)目的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Java實(shí)現(xiàn)簡易圖書借閱系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡易圖書借閱系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
SpringBoot+微信小程序?qū)崿F(xiàn)文件上傳與下載功能詳解
這篇文章主要為大家介紹了SpringBoot整合微信小程序?qū)崿F(xiàn)文件上傳與下載功能,文中的實(shí)現(xiàn)步驟講解詳細(xì),快跟隨小編一起學(xué)習(xí)一下吧2022-03-03
Spring security實(shí)現(xiàn)權(quán)限管理示例
這篇文章主要介紹了Spring security實(shí)現(xiàn)權(quán)限管理示例,這里整理了詳細(xì)的代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-01-01

