成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

并發(fā)——讀寫(xiě)鎖初探

everfly / 2893人閱讀

適用場(chǎng)景

讀操作頻發(fā),寫(xiě)操作不頻繁。

兩個(gè)線程同時(shí)讀取同一個(gè)共享資源沒(méi)有任何問(wèn)題

如果一個(gè)線程對(duì)共享資源進(jìn)行寫(xiě)操作,此時(shí)就不能有其他線程對(duì)共享資源進(jìn)行讀寫(xiě)

條件分析

寫(xiě)操作的優(yōu)先級(jí)高于讀操作,在讀操作頻繁的場(chǎng)景下,如果寫(xiě)操作沒(méi)有高于讀操作的優(yōu)先級(jí),就會(huì)導(dǎo)致寫(xiě)操作線程“餓死”的情況發(fā)生

讀操作觸發(fā)條件:

沒(méi)有線程正在執(zhí)行寫(xiě)操作

沒(méi)有線程在等待執(zhí)行寫(xiě)操作

寫(xiě)操作觸發(fā)條件:沒(méi)有線程正在執(zhí)行讀寫(xiě)操作

代碼實(shí)現(xiàn)
public class ReadWriteLock {

??private int readers = 0;
??private int writers = 0;
??private int writeRequests = 0;

??public synchronized void lockRead() throws InterruptedException {

????while (writers > 0 || writeRequests > 0) {
??????wait();
????}
????readers++;
??}

??public synchronized void unlockRead() {
????readers--;
????notifyAll();
??}

??public synchronized void lockWrite() throws InterruptedException {

????writeRequests++;
????while (readers > 0 || writers > 0) {
??????wait();
????}

????writeRequests--;
????writers++;
??}

??public synchronized void unlockWrite() throws InterruptedException {

????writers--;
????notifyAll();
??}
}
ReadWriteLockl類中通過(guò)讀鎖、寫(xiě)鎖以兩個(gè)鎖的狀態(tài)控制線程的讀、寫(xiě)操作:
writers表示當(dāng)前正在使用寫(xiě)鎖的線程數(shù)量;
writeRequests表示等待請(qǐng)求寫(xiě)鎖的線程數(shù)量;
readers表示請(qǐng)求讀鎖的線程數(shù)量;
說(shuō)明:
1.線程在獲取讀鎖的時(shí)候,只要沒(méi)有線程擁有寫(xiě)鎖即writers==0同時(shí)沒(méi)有線程請(qǐng)求寫(xiě)鎖即writerRquests==0,那么線程就能成功獲取讀鎖;
2.當(dāng)一個(gè)線程想獲取寫(xiě)鎖的時(shí)候,會(huì)把寫(xiě)鎖的請(qǐng)求數(shù)加1即writeRequests++,然后再嘗試獲取能否獲取寫(xiě)鎖,如果當(dāng)前沒(méi)有線程占用寫(xiě)鎖即writers==0,那么此時(shí)就能成功獲取寫(xiě)鎖,同時(shí)writers++;如果wirters>0表示寫(xiě)鎖此時(shí)被其他線程占用那么當(dāng)前線程會(huì)被阻塞等待寫(xiě)鎖釋放時(shí)被喚醒。
3.寫(xiě)操作的優(yōu)先級(jí)高于讀操作的優(yōu)先級(jí)體現(xiàn)在,線程請(qǐng)求讀鎖時(shí)會(huì)判斷持有寫(xiě)鎖的線程數(shù)和請(qǐng)求寫(xiě)鎖的線程數(shù),即while(writers > 0 || writeRequests > 0){wait();},而線程請(qǐng)求寫(xiě)鎖時(shí)只需要判斷持有寫(xiě)鎖和讀鎖的線程數(shù)即可,即while(readers > 0 || writers > 0) {wait();}
鎖重入

鎖重入,是指同一線程 外層函數(shù)獲得鎖之后 ,內(nèi)層遞歸函數(shù)仍然有獲取該鎖的代碼,但不受影響。ReentrantLock 和synchronized 都是可重入鎖,可重入鎖最大的作用是避免死鎖。
以自旋鎖為例,如果自旋鎖不是可重入鎖的話,如果一個(gè)線程在第一次獲取鎖執(zhí)行同步代碼前提下,第二次再執(zhí)行同步代碼就產(chǎn)生了死鎖。
以前面的代碼為例:

此時(shí)有兩個(gè)線程Thread1,Thread2

Thread2在Thread1獲取讀鎖以后請(qǐng)求寫(xiě)鎖,readers=1、writers=0、writeRequests=1

若此時(shí)Thread1再次嘗試獲取同一個(gè)讀鎖,根據(jù)已有的代碼writers > 0 || writeRequests > 0,因?yàn)門(mén)hread請(qǐng)求寫(xiě)鎖的原因?qū)е略摋l件成立,Thread1進(jìn)入阻塞狀態(tài),死鎖出現(xiàn)

讀鎖重入
public class ReadWriteLock{

?private Map readingThreads = new HashMap();
?private int writers = 0;
?private int writeRequests = 0;

?public synchronized void lockRead() throws InterruptedException{
???Thread callingThread = Thread.currentThread();
???while(! canGrantReadAccess(callingThread)){
?????wait();
???}
???readingThreads.put(callingThread, (getAccessCount(callingThread) + 1));
?}

?public synchronized void unlockRead(){
???Thread callingThread = Thread.currentThread();
???int accessCount = getAccessCount(callingThread);
???if(accessCount == 1) {
????readingThreads.remove(callingThread);
???} else {
????readingThreads.put(callingThread, (accessCount -1));
???}
???notifyAll();
?}

?private boolean canGrantReadAccess(Thread callingThread){
???if(writers > 0) return false;
???if(isReader(callingThread) return true;
???if(writeRequests > 0) return false;
???return true;
?}

?private int getReadAccessCount(Thread callingThread){
???Integer accessCount = readingThreads.get(callingThread);
???if(accessCount == null) return 0;
???return accessCount.intValue();
}

?private boolean isReader(Thread callingThread){
???return readingThreads.get(callingThread) != null;
?}
}
讀鎖的可重入有兩種情況:
1.當(dāng)前程序中沒(méi)有線程請(qǐng)求寫(xiě)鎖(這種情況是幾乎不存在)
2.當(dāng)前程序中有線程請(qǐng)求寫(xiě)鎖也有線程請(qǐng)求讀鎖,并且有線程已經(jīng)得到了讀鎖

第二種情況是最常見(jiàn)的,因此我們需要知道哪些線程是持有讀鎖的

因此在代碼中使用Map來(lái)存儲(chǔ)已經(jīng)持有讀鎖的線程和對(duì)應(yīng)線程獲取讀鎖的次數(shù),通過(guò)Map就可以判斷對(duì)應(yīng)的線程是否持有讀鎖,調(diào)整之后的代碼在原有判斷"writeRequests >0"和"writers > 0"還加上了判斷當(dāng)前線程是否持有讀鎖的判斷邏輯
寫(xiě)鎖重入
public class ReadWriteLock{
?private Map readingThreads = new HashMap();
?private int writeAccesses = 0;
?private int writeRequests = 0;
?private Thread writingThread = null;

?public synchronized void lockWrite() throws InterruptedException{

???writeRequests++;
???Thread callingThread = Thread.currentThread();
???while(!canGrantWriteAccess(callingThread)){
????wait();
???}
???writeRequests--;
???writeAccesses++;
???writingThread = callingThread;
?}

?public synchronized void unlockWrite() throws InterruptedException{
???writeAccesses--;
???if(writeAccesses == 0){
?????writingThread = null;
???}
???notifyAll();
?}

?private boolean canGrantWriteAccess(Thread callingThread){
???if(hasReaders()) return false;
???if(writingThread == null) return true;
???if(!isWriter(callingThread)) return false;
???return true;
?}

?private boolean hasReaders(){
???return readingThreads.size() > 0;
?}

?private boolean isWriter(Thread callingThread){
???return writingThread == callingThread;
?}
}
寫(xiě)鎖重入,是在當(dāng)前程序里有且只有一個(gè)線程持有寫(xiě)鎖,如果寫(xiě)鎖重入,說(shuō)明當(dāng)前程序中沒(méi)有線程持有讀鎖,寫(xiě)鎖重入只有持有寫(xiě)鎖的線程才能重入,其他的線程就需要進(jìn)入阻塞狀態(tài)
讀寫(xiě)鎖完整代碼
public class ReadWriteLock{

    private Map readingThreads = new HashMap();
    private int writeAccesses = 0;
    private int writeRequests = 0;
    private Thread writingThread = null;

    public synchronized void lockRead() throws InterruptedException{
     Thread callingThread = Thread.currentThread();
     while(! canGrantReadAccess(callingThread)){
         wait();
     }
     readingThreads.put(callingThread,(getReadAccessCount(callingThread) + 1));
    }

    private boolean canGrantReadAccess(Thread callingThread){
     #寫(xiě)鎖降級(jí)到讀鎖的邏輯判斷
     if(isWriter(callingThread)) return true;
     if(hasWriter()) return false;
     if(isReader(callingThread)) return true;
     if(hasWriteRequests()) return false;
     return true;
    }

    public synchronized void unlockRead(){
     Thread callingThread = Thread.currentThread();
     if(!isReader(callingThread)){
        throw new IllegalMonitorStateException(
             "Calling Thread does not" +
             " hold a read lock on this ReadWriteLock");
     }

     int accessCount = getReadAccessCount(callingThread);
     if(accessCount == 1){
         readingThreads.remove(callingThread);
     } else {
         readingThreads.put(callingThread, (accessCount -1));
     }
     notifyAll();
    }

    public synchronized void lockWrite() throws InterruptedException{
     writeRequests++;
     Thread callingThread = Thread.currentThread();
     while(!canGrantWriteAccess(callingThread)){
         wait();
     }
     writeRequests--;
     writeAccesses++;
     writingThread = callingThread;
    }

    public synchronized void unlockWrite() throws InterruptedException{
     if(!isWriter(Thread.currentThread()){
        throw new IllegalMonitorStateException(
         "Calling Thread does not" +
         " hold the write lock on this ReadWriteLock");
     }
     writeAccesses--;
     if(writeAccesses == 0){
         writingThread = null;
     }
     notifyAll();
    }

    private boolean canGrantWriteAccess(Thread callingThread){
     #讀鎖轉(zhuǎn)換成寫(xiě)鎖的邏輯判斷
     if(isOnlyReader(callingThread)) return true;
     if(hasReaders()) return false;
     if(writingThread == null) return true;
     if(!isWriter(callingThread)) return false;
     return true;
    }

    private int getReadAccessCount(Thread callingThread){
     Integer accessCount = readingThreads.get(callingThread);
     if(accessCount == null) return 0;
     return accessCount.intValue();
    }

    private boolean hasReaders(){
     return readingThreads.size() > 0;
    }

    private boolean isReader(Thread callingThread){
     return readingThreads.get(callingThread) != null;
    }

    private boolean isOnlyReader(Thread callingThread){
     return readingThreads.size() == 1 && readingThreads.get(callingThread) != null;
    }

    private boolean hasWriter(){
     return writingThread != null;
    }

    private boolean isWriter(Thread callingThread){
     return writingThread == callingThread;
    }

    private boolean hasWriteRequests(){
     return this.writeRequests > 0;
    }
}

參考文獻(xiàn)
http://ifeve.com/read-write-l...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/71556.html

相關(guān)文章

  • [Java并發(fā)-6]“管程”-java管程初探

    摘要:語(yǔ)言在之前,提供的唯一的并發(fā)原語(yǔ)就是管程,而且之后提供的并發(fā)包,也是以管程技術(shù)為基礎(chǔ)的。但是管程更容易使用,所以選擇了管程。線程進(jìn)入條件變量的等待隊(duì)列后,是允許其他線程進(jìn)入管程的。并發(fā)編程里兩大核心問(wèn)題互斥和同步,都可以由管程來(lái)幫你解決。 并發(fā)編程這個(gè)技術(shù)領(lǐng)域已經(jīng)發(fā)展了半個(gè)世紀(jì)了。有沒(méi)有一種核心技術(shù)可以很方便地解決我們的并發(fā)問(wèn)題呢?這個(gè)問(wèn)題, 我會(huì)選擇 Monitor(管程)技術(shù)。Ja...

    Steve_Wang_ 評(píng)論0 收藏0
  • [Java并發(fā)-10] ReadWriteLock:快速實(shí)現(xiàn)一個(gè)完備的緩存

    摘要:此時(shí)線程和會(huì)再有一個(gè)線程能夠獲取寫(xiě)鎖,假設(shè)是,如果不采用再次驗(yàn)證的方式,此時(shí)會(huì)再次查詢數(shù)據(jù)庫(kù)。而實(shí)際上線程已經(jīng)把緩存的值設(shè)置好了,完全沒(méi)有必要再次查詢數(shù)據(jù)庫(kù)。 大家知道了Java中使用管程同步原語(yǔ),理論上可以解決所有的并發(fā)問(wèn)題。那 Java SDK 并發(fā)包里為什么還有很多其他的工具類呢?原因很簡(jiǎn)單:分場(chǎng)景優(yōu)化性能,提升易用性 今天我們就介紹一種非常普遍的并發(fā)場(chǎng)景:讀多寫(xiě)少場(chǎng)景。實(shí)際工作...

    nevermind 評(píng)論0 收藏0
  • Java 中15種的介紹:公平,可重入,獨(dú)享,互斥,樂(lè)觀,分段,自旋等等

    摘要:公平鎖非公平鎖公平鎖公平鎖是指多個(gè)線程按照申請(qǐng)鎖的順序來(lái)獲取鎖。加鎖后,任何其他試圖再次加鎖的線程會(huì)被阻塞,直到當(dāng)前進(jìn)程解鎖。重量級(jí)鎖會(huì)讓其他申請(qǐng)的線程進(jìn)入阻塞,性能降低。 Java 中15種鎖的介紹 在讀很多并發(fā)文章中,會(huì)提及各種各樣鎖如公平鎖,樂(lè)觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內(nèi)容如下: 公平鎖 / 非公平鎖 可重入鎖 / 不可重入鎖 獨(dú)享鎖 / 共享鎖 互斥鎖 / 讀...

    LeoHsiun 評(píng)論0 收藏0
  • 實(shí)戰(zhàn)java高并發(fā)程序設(shè)計(jì)第四章-優(yōu)化

    摘要:鎖的使用建議減少鎖持有時(shí)間減少鎖粒度讀寫(xiě)鎖替代獨(dú)占鎖鎖分離鎖粗化減少鎖的持有時(shí)間減少鎖的持有時(shí)間有助于降低沖突的可能性進(jìn)而提升并發(fā)能力減少鎖粒度例如內(nèi)部分為個(gè)加鎖時(shí)不會(huì)像一樣全局加鎖只需要對(duì)相應(yīng)加鎖但是如果需要獲取全局的信息比如首先會(huì)使用無(wú) 鎖的使用建議 減少鎖持有時(shí)間 減少鎖粒度 讀寫(xiě)鎖替代獨(dú)占鎖 鎖分離 鎖粗化 減少鎖的持有時(shí)間 減少鎖的持有時(shí)間有助于降低沖突的可能性,進(jìn)而...

    W_BinaryTree 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<