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

Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解

 更新時(shí)間:2023年02月18日 16:40:27   投稿:wdc  
這篇文章主要介紹了Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解,讀寫(xiě)狀態(tài)的設(shè)計(jì),寫(xiě)鎖的獲取與釋放,鎖降級(jí)需要的朋友可以參考下

Java并發(fā)編程提供了讀寫(xiě)鎖,主要用于讀多寫(xiě)少的場(chǎng)景

什么是讀寫(xiě)鎖?

讀寫(xiě)鎖并不是JAVA所特有的讀寫(xiě)鎖(Readers-Writer Lock)顧名思義是一把鎖分為兩部分:讀鎖和寫(xiě)鎖,其中讀鎖允許多個(gè)線程同時(shí)獲得,因?yàn)樽x操作本身是線程安全的,而寫(xiě)鎖則是互斥鎖,不允許多個(gè)線程同時(shí)獲得寫(xiě)鎖,并且寫(xiě)操作和讀操作也是互斥的。

所謂的讀寫(xiě)鎖(Readers-Writer Lock),顧名思義就是將一個(gè)鎖拆分為讀鎖和寫(xiě)鎖兩個(gè)鎖。

其中讀鎖允許多個(gè)線程同時(shí)獲得,而寫(xiě)鎖則是互斥鎖,不允許多個(gè)線程同時(shí)獲得寫(xiě)鎖,并且寫(xiě)操作和讀操作也是互斥的。

Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解-mikechen的互聯(lián)網(wǎng)架構(gòu)

為什么需要讀寫(xiě)鎖?

Synchronized 和 ReentrantLock 都是獨(dú)占鎖,即在同一時(shí)刻只有一個(gè)線程獲取到鎖。

然而在有些業(yè)務(wù)場(chǎng)景中,我們大多在讀取數(shù)據(jù),很少寫(xiě)入數(shù)據(jù),這種情況下,如果仍使用獨(dú)占鎖,效率將及其低下。

針對(duì)這種情況,Java提供了讀寫(xiě)鎖——ReentrantReadWriteLock。

主要解決:對(duì)共享資源有讀和寫(xiě)的操作,且寫(xiě)操作沒(méi)有讀操作那么頻繁的場(chǎng)景。

讀寫(xiě)鎖的特點(diǎn)

  • 公平性:讀寫(xiě)鎖支持非公平和公平的鎖獲取方式,非公平鎖的吞吐量?jī)?yōu)于公平鎖的吞吐量,默認(rèn)構(gòu)造的是非公平鎖
  • 可重入:在線程獲取讀鎖之后能夠再次獲取讀鎖,但是不能獲取寫(xiě)鎖,而線程在獲取寫(xiě)鎖之后能夠再次獲取寫(xiě)鎖,同時(shí)也能獲取讀鎖
  • 鎖降級(jí):線程獲取寫(xiě)鎖之后獲取讀鎖,再釋放寫(xiě)鎖,這樣實(shí)現(xiàn)了寫(xiě)鎖變?yōu)樽x鎖,也叫鎖降級(jí)

讀寫(xiě)鎖的使用場(chǎng)景

ReentrantReadWriteLock適合讀多寫(xiě)少的場(chǎng)景:

讀鎖ReentrantReadWriteLock.ReadLock可以被多個(gè)線程同時(shí)持有, 所以并發(fā)能力很高。

寫(xiě)鎖ReentrantReadWriteLock.WriteLock是獨(dú)占鎖, 在一個(gè)線程持有寫(xiě)鎖時(shí)候, 其他線程都不能在搶占, 包含搶占讀鎖都會(huì)阻塞。

ReentrantReadWriteLock的使用場(chǎng)景總結(jié):其實(shí)就是 讀讀并發(fā)、讀寫(xiě)互斥、寫(xiě)寫(xiě)互斥而已,如果一個(gè)對(duì)象并發(fā)讀的場(chǎng)景大于并發(fā)寫(xiě)的場(chǎng)景,那就可以使用 ReentrantReadWriteLock來(lái)達(dá)到保證線程安全的前提下提高并發(fā)效率。

讀寫(xiě)鎖的主要成員和結(jié)構(gòu)圖

1. ReentrantReadWriteLock的繼承關(guān)系

Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解-mikechen的互聯(lián)網(wǎng)架構(gòu)

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading.
     */
    Lock readLock();
    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing.
     */
    Lock writeLock();
}

讀寫(xiě)鎖 ReadWriteLock

讀寫(xiě)鎖維護(hù)了一對(duì)相關(guān)的鎖,一個(gè)用于只讀操作,一個(gè)用于寫(xiě)入操作。

只要沒(méi)有寫(xiě)入,讀取鎖可以由多個(gè)讀線程同時(shí)保持,寫(xiě)入鎖是獨(dú)占的。

2.ReentrantReadWriteLock的核心變量

Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解-mikechen的互聯(lián)網(wǎng)架構(gòu)

ReentrantReadWriteLock類(lèi)包含三個(gè)核心變量:

  • ReaderLock:讀鎖,實(shí)現(xiàn)了Lock接口
  • WriterLock:寫(xiě)鎖,也實(shí)現(xiàn)了Lock接口
  • Sync:繼承自AbstractQueuedSynchronize(AQS),可以為公平鎖FairSync 或 非公平鎖NonfairSync

3.ReentrantReadWriteLock的成員變量和構(gòu)造函數(shù)

/** 內(nèi)部提供的讀鎖 */

    private final ReentrantReadWriteLock.ReadLock readerLock;

    /** 內(nèi)部提供的寫(xiě)鎖 */
    private final ReentrantReadWriteLock.WriteLock writerLock;

    /** AQS來(lái)實(shí)現(xiàn)的同步器 */
    final Sync sync;

    /**
     * Creates a new {@code ReentrantReadWriteLock} with
     * 默認(rèn)創(chuàng)建非公平的讀寫(xiě)鎖
     */
    public ReentrantReadWriteLock() {
        this(false);
    }

    /**
     * Creates a new {@code ReentrantReadWriteLock} with
     * the given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

讀寫(xiě)鎖的實(shí)現(xiàn)原理

ReentrantReadWriteLock實(shí)現(xiàn)關(guān)鍵點(diǎn),主要包括:

  • 讀寫(xiě)狀態(tài)的設(shè)計(jì)
  • 寫(xiě)鎖的獲取與釋放
  • 讀鎖的獲取與釋放
  • 鎖降級(jí)

1.讀寫(xiě)狀態(tài)的設(shè)計(jì)

之前談ReentrantLock的時(shí)候,Sync類(lèi)是繼承于AQS,主要以int state為線程鎖狀態(tài),0表示沒(méi)有被線程占用,1表示已經(jīng)有線程占用。

同樣ReentrantReadWriteLock也是繼承于AQS來(lái)實(shí)現(xiàn)同步,那int state怎樣同時(shí)來(lái)區(qū)分讀鎖和寫(xiě)鎖的?

如果在一個(gè)整型變量上維護(hù)多種狀態(tài),就一定需要“按位切割使用”這個(gè)變量,ReentrantReadWriteLock將int類(lèi)型的state將變量切割成兩部分:

  • 高16位記錄讀鎖狀態(tài)
  • 低16位記錄寫(xiě)鎖狀態(tài)

Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解-mikechen的互聯(lián)網(wǎng)架構(gòu)

abstract static class Sync extends AbstractQueuedSynchronizer {
    // 版本序列號(hào)
    private static final long serialVersionUID = 6317671515068378041L;        
    // 高16位為讀鎖,低16位為寫(xiě)鎖
    static final int SHARED_SHIFT   = 16;
    // 讀鎖單位
    static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
    // 讀鎖最大數(shù)量
    static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
    // 寫(xiě)鎖最大數(shù)量
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
    // 本地線程計(jì)數(shù)器
    private transient ThreadLocalHoldCounter readHolds;
    // 緩存的計(jì)數(shù)器
    private transient HoldCounter cachedHoldCounter;
    // 第一個(gè)讀線程
    private transient Thread firstReader = null;
    // 第一個(gè)讀線程的計(jì)數(shù)
    private transient int firstReaderHoldCount;
}

2.寫(xiě)鎖的獲取與釋放

protected final boolean tryAcquire(int acquires) {
            /*
             * Walkthrough:
             * 1. If read count nonzero or write count nonzero
             *    and owner is a different thread, fail.
             * 2. If count would saturate, fail. (This can only
             *    happen if count is already nonzero.)
             * 3. Otherwise, this thread is eligible for lock if
             *    it is either a reentrant acquire or
             *    queue policy allows it. If so, update state
             *    and set owner.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            //獲取獨(dú)占鎖(寫(xiě)鎖)的被獲取的數(shù)量
            int w = exclusiveCount(c);
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                //1.如果同步狀態(tài)不為0,且寫(xiě)狀態(tài)為0,則表示當(dāng)前同步狀態(tài)被讀鎖獲取
                //2.或者當(dāng)前擁有寫(xiě)鎖的線程不是當(dāng)前線程
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);
                return true;
            }
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }

1)c是獲取當(dāng)前鎖狀態(tài),w是獲取寫(xiě)鎖的狀態(tài)。

2)如果鎖狀態(tài)不為零,而寫(xiě)鎖的狀態(tài)為0,則表示讀鎖狀態(tài)不為0,所以當(dāng)前線程不能獲取寫(xiě)鎖。或者鎖狀態(tài)不為零,而寫(xiě)鎖的狀態(tài)也不為0,但是獲取寫(xiě)鎖的線程不是當(dāng)前線程,則當(dāng)前線程不能獲取寫(xiě)鎖。

3)寫(xiě)鎖是一個(gè)可重入的排它鎖,在獲取同步狀態(tài)時(shí),增加了一個(gè)讀鎖是否存在的判斷。

寫(xiě)鎖的釋放與ReentrantLock的釋放過(guò)程類(lèi)似,每次釋放將寫(xiě)狀態(tài)減1,直到寫(xiě)狀態(tài)為0時(shí),才表示該寫(xiě)鎖被釋放了。

3.讀鎖的獲取與釋放

protected final int tryAcquireShared(int unused) {
    for(;;) {
        int c = getState();
        int nextc = c + (1<<16);
        if(nextc < c) {
           throw new Error("Maxumum lock count exceeded");
        }
        if(exclusiveCount(c)!=0 && owner != Thread.currentThread())
           return -1;
        if(compareAndSetState(c,nextc))
           return 1;
    }
}

1)讀鎖是一個(gè)支持重進(jìn)入的共享鎖,可以被多個(gè)線程同時(shí)獲取。

2)在沒(méi)有寫(xiě)狀態(tài)為0時(shí),讀鎖總會(huì)被成功獲取,而所做的也只是增加讀狀態(tài)(線程安全)

3)讀狀態(tài)是所有線程獲取讀鎖次數(shù)的總和,而每個(gè)線程各自獲取讀鎖的次數(shù)只能選擇保存在ThreadLocal中,由線程自身維護(hù)。

讀鎖的每次釋放均減小狀態(tài)(線程安全的,可能有多個(gè)讀線程同時(shí)釋放鎖),減小的值是1<<16。

4.鎖降級(jí)

降級(jí)是指當(dāng)前把持住寫(xiě)鎖,再獲取到讀鎖,隨后釋放(先前擁有的)寫(xiě)鎖的過(guò)程。

鎖降級(jí)過(guò)程中的讀鎖的獲取是否有必要,答案是必要的。主要是為了保證數(shù)據(jù)的可見(jiàn)性,如果當(dāng)前線程不獲取讀鎖而直接釋放寫(xiě)鎖,假設(shè)此刻另一個(gè)線程獲取的寫(xiě)鎖,并修改了數(shù)據(jù),那么當(dāng)前線程就步伐感知到線程T的數(shù)據(jù)更新,如果當(dāng)前線程遵循鎖降級(jí)的步驟,那么線程T將會(huì)被阻塞,直到當(dāng)前線程使數(shù)據(jù)并釋放讀鎖之后,線程T才能獲取寫(xiě)鎖進(jìn)行數(shù)據(jù)更新。

5.讀鎖與寫(xiě)鎖的整體流程

Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解-mikechen的互聯(lián)網(wǎng)架構(gòu)

讀寫(xiě)鎖總結(jié)

本篇詳細(xì)介紹了ReentrantReadWriteLock的特征、實(shí)現(xiàn)、鎖的獲取過(guò)程,通過(guò)4個(gè)關(guān)鍵點(diǎn)的核心設(shè)計(jì):

  • 讀寫(xiě)狀態(tài)的設(shè)計(jì)
  • 寫(xiě)鎖的獲取與釋放
  • 讀鎖的獲取與釋放
  • 鎖降級(jí)

從而才能實(shí)現(xiàn):共享資源有讀和寫(xiě)的操作,且寫(xiě)操作沒(méi)有讀操作那么頻繁的應(yīng)用場(chǎng)景。

以上就是Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景詳解的詳細(xì)內(nèi)容,更多關(guān)于Java讀寫(xiě)鎖ReadWriteLock原理與應(yīng)用場(chǎng)景的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 輸出java進(jìn)程的jstack信息示例分享 通過(guò)線程堆棧信息分析java線程

    輸出java進(jìn)程的jstack信息示例分享 通過(guò)線程堆棧信息分析java線程

    通過(guò)ps到j(luò)ava進(jìn)程號(hào)將進(jìn)程的jstack信息輸出。jstack信息是java進(jìn)程的線程堆棧信息,通過(guò)該信息可以分析java的線程阻塞等問(wèn)題。
    2014-01-01
  • Java創(chuàng)建文件夾及文件實(shí)例代碼

    Java創(chuàng)建文件夾及文件實(shí)例代碼

    Java創(chuàng)建文件夾及文件實(shí)例代碼,需要的朋友可以參考一下
    2013-04-04
  • 解決maven?maven.compiler.source和maven.compiler.target的坑

    解決maven?maven.compiler.source和maven.compiler.target的坑

    這篇文章主要介紹了解決maven?maven.compiler.source和maven.compiler.target的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring5新特性之Reactive響應(yīng)式編程

    Spring5新特性之Reactive響應(yīng)式編程

    這篇文章主要介紹了Spring5新特性之Reactive響應(yīng)式編程,響應(yīng)式編程是一種編程范式,通用和專(zhuān)注于數(shù)據(jù)流和變化的,并且是異步的,下文更多詳細(xì)內(nèi)容,需要的小伙伴可以參考一下,希望對(duì)你有所幫助
    2022-03-03
  • spring AOP的Around增強(qiáng)實(shí)現(xiàn)方法分析

    spring AOP的Around增強(qiáng)實(shí)現(xiàn)方法分析

    這篇文章主要介紹了spring AOP的Around增強(qiáng)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了spring面向切面AOP的Around增強(qiáng)具體步驟與相關(guān)操作方法,需要的朋友可以參考下
    2020-01-01
  • Java內(nèi)存溢出案例模擬和原理分析過(guò)程

    Java內(nèi)存溢出案例模擬和原理分析過(guò)程

    這篇文章主要介紹了Java內(nèi)存溢出案例模擬和原理分析過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • SpringBoot整合MyBatis-Plus的示例代碼

    SpringBoot整合MyBatis-Plus的示例代碼

    這篇文章主要介紹了SpringBoot整合MyBatis-Plus的示例代碼,使用?MyBatis-Plus 可以減少大量的開(kāi)發(fā)時(shí)間,單表的增刪改查可以不用寫(xiě) sql 語(yǔ)句,本文主要介紹整合需要主要事項(xiàng),需要的朋友可以參考下
    2022-03-03
  • Spring 中@Validated 分組校驗(yàn)的使用解析

    Spring 中@Validated 分組校驗(yàn)的使用解析

    這篇文章主要介紹了Spring 中@Validated 分組校驗(yàn)的使用解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Mybatis各種查詢(xún)接口使用詳解

    Mybatis各種查詢(xún)接口使用詳解

    這篇文章主要介紹了Mybatis各種查詢(xún)接口使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-11-11
  • 關(guān)于集合和字符串的互轉(zhuǎn)實(shí)現(xiàn)方法

    關(guān)于集合和字符串的互轉(zhuǎn)實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇關(guān)于集合和字符串的互轉(zhuǎn)實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08

最新評(píng)論