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

Java公平鎖與非公平鎖的核心原理講解

 更新時間:2022年11月02日 10:04:31   作者:小威要向諸佬學習呀  
從公平的角度來說,Java 中的鎖總共可分為兩類:公平鎖和非公平鎖。但公平鎖和非公平鎖有哪些區(qū)別?核心原理是什么?本文就來和大家詳細聊聊

Lock鎖接口方法

前面了解到了synchronized鎖,也知道了synchronized鎖是一種JVM提供內(nèi)置鎖,但synchronized有一些缺點:比如不支持響應中斷,不支持超時,不支持以非阻塞的方式獲取鎖等。而今天的主角Lock鎖,需要我們手動獲取鎖和釋放鎖,里面有很多方式來獲取鎖,比如以阻塞方式獲取鎖,在指定時間內(nèi)獲取鎖,非阻塞模式下?lián)屨兼i等,其方法源碼如下(位于package java.util.concurrent.locks包下):

//Lock接口下的方法
public interface Lock {
    //阻塞式搶占鎖,如果搶到鎖,則向下執(zhí)行程序;搶占失敗線程阻塞,直到釋放鎖才會進行搶占鎖
    void lock();
    //可中斷模式搶占鎖,線程調(diào)用此方法能夠中斷線程
    void lockInterruptibly() throws InterruptedException;
    //非阻塞式嘗試獲取鎖,調(diào)用此方法線程不會阻塞,搶到鎖返回true,失敗返回false
    boolean tryLock();
    //在指定時間內(nèi)嘗試獲取鎖,在指定時間內(nèi)搶到鎖成功返回true,失敗返回false
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    //釋放鎖,線程執(zhí)行完程序后,調(diào)用此方法來釋放鎖資源
    void unlock();
    //條件隊列
    Condition newCondition();
    }

公平鎖簡介

公平鎖,顧名思義,所有線程獲取鎖都是公平的。在多線程并發(fā)情況下,線程爭搶鎖時,首先會檢查等待隊列中是否有其他線程在等待。如果等待隊列為空,沒有線程在等待,那么當前線程會拿到鎖資源;如果等待隊列中有其他線程在等待,那么當前線程會排到等待隊列的尾部,好比我們排隊買東西一樣。

ReentranLock的公平鎖

ReentranLock類實現(xiàn)了Lock接口,重寫了里面的方法,對于ReentranLock類中的公平鎖,我們可以看到如下源碼:

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

在上述構造方法中,新建鎖對象是否為公平鎖,在于傳入的參數(shù)是true還是false,在三目運算符中,如果傳入?yún)?shù)為true,則會創(chuàng)建一個FairSync()對象賦值給sync,線程獲取的鎖是公平鎖;如果為false則創(chuàng)建一個NonfairSync()對象,線程獲取的鎖是非公平鎖。點入FairSync()方法,得到如下源碼:

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }
        /*這里將acquire方法放于此
            public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
        */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //拿到當前鎖對象的狀態(tài)
            int c = getState();
            //如果沒有線程獲取到鎖
            if (c == 0) {
                //首先會判斷是否有前驅節(jié)點,如果沒有就會調(diào)用CAS機制更新鎖對象狀態(tài)
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    //設置當前線程擁有鎖資源
                    setExclusiveOwnerThread(current);
                    //如果獲取鎖資源成功則返回true
                    return true;
                }
            }
            //或者如果拿到鎖的就是當前線程
            else if (current == getExclusiveOwnerThread()) {
                //將鎖的狀態(tài)+1,考慮到鎖重入
                int nextc = c + acquires;
                if (nextc < 0)
                    //超過了最大鎖的數(shù)量
                    throw new Error("Maximum lock count exceeded");
                //如果鎖數(shù)量沒有溢出,設置當前鎖狀態(tài)
                setState(nextc);
                //如果成功獲取鎖資源則返回true
                return true;
            }
            //如果前兩條都不符合,則返回false
            return false;
        }
    }

上述代碼涉及到了hasQueuedPredecessors()方法,返回true則代表有有前驅節(jié)點,點入查看得到以下源碼:

    public final boolean hasQueuedPredecessors() {
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        //h!=t,首節(jié)點不等于尾節(jié)點表示隊列中有節(jié)點
        return h != t &&
            (
            //s為頭結點的下一個節(jié)點,返回false表示隊列中還有第二個節(jié)點,或運算符后面表示,第二個線程不是當前線程
            (s = h.next) == null || s.thread != Thread.currentThread()
            );
    }

因此做出總結,使用ReentranLock的公平鎖,當線程調(diào)用ReentranLock類中的lock()方法時,會首先調(diào)用FairSync類中的lock()方法;然后FairSync類中的lock()方法會調(diào)用AQS類(AbstractQueuedSynchronizer)中的acquire(1)方法獲取資源,前面的文章里也提到過,acquire()方法會調(diào)用tryAcquire()方法嘗試獲取鎖,tryAcquire()方法里面沒有具體的實現(xiàn),tryAcquire()方法具體邏輯是由其子類實現(xiàn)的,因此調(diào)用的還是FairSync類中的方法。在AQS中的acquire()方法中如果嘗試獲取資源失敗,會調(diào)用addWaiter()方法將當前線程封裝為Node節(jié)點放到等待隊列的尾部,并且調(diào)用AQS中的acquireQueued方法使線程在等待隊列中排隊。

ReentranLock的非公平鎖

非公平鎖就是所有搶占鎖的線程都是不公平的,在我們?nèi)粘I钪芯拖喈斢谑遣尻牞F(xiàn)象,不過也與插隊稍微不同。在多線程并發(fā)時,每個線程在搶占鎖的過程中,都會先嘗試獲取鎖,如果獲取成功,則直接指向具體的業(yè)務邏輯;如果獲取鎖失敗,則會像公平鎖一樣在等待隊列隊尾等待。

在非公平鎖模式下,由于剛來的線程可以在隊首位置進行一次插隊,所以當插隊成功時,后面的線程可能會出現(xiàn)長時間等待,無法獲取鎖資源產(chǎn)生饑餓現(xiàn)象。但是非公平鎖性能比公平鎖性能更好。

對于ReentranLock類中的非公平鎖,實現(xiàn)方式有兩種,一種是默認的構造方式,另一種是和上面的一樣,源碼如下:

    //第一種方式,默認實現(xiàn)
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    //第二種方式,傳入false來創(chuàng)建非公平鎖對象
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

對于創(chuàng)建的NonfairSync()類對象,其源碼如下:

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

 

在上述代碼中,當線程獲取鎖時,并沒有直接將當前線程放入等待隊列中,而是先嘗試獲取鎖資源,如果獲取鎖成功,設置state標志位1成功,則直接將當前線程拿到鎖,執(zhí)行線程業(yè)務;如果獲取鎖資源失敗,則調(diào)用AQS中的acquire方法獲取資源,而acquire()方法會回調(diào)上面NonfairSyn類中的tryAcquire()方法,然后又會回調(diào)Sync類中的nonfairTryAcquire()方法(NonfairSync類繼承了Sync類) ,點擊nonfairTryAcquire(acquires)查看源碼:

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

由上訴代碼,沒有將線程放入到等待隊列中,只是對鎖的狀態(tài)進行了判斷,若標識為0,代表沒有線程拿到鎖,當前線程會使用CAS機制改變鎖狀態(tài),并調(diào)用setExclusiveOwnerThread(current)方法讓當前線程拿到鎖。

因此綜上所述,在使用ReentranLock中的非公平鎖時,首先會調(diào)用lock()方法,,而ReentranLock類中l(wèi)ock()方法會調(diào)用NonfairSync類中的lock()方法,接著NonfairSync類中的lock()方法會調(diào)用AQS中的acquire()方法來獲取鎖資源,AQS中的acquire()方法又會回調(diào)NonfairSync類中tryAcquire()方法嘗試獲取資源,NonfairSync類中tryAcquire()方法會調(diào)用Sync類中的nonfairTryAcquire方法嘗試非公平鎖獲取資源;獲取失敗的話,AQS中的acquire()方法會調(diào)用addWaiter()方法將當前線程封裝成Node節(jié)點放入到等待隊列的隊尾,而后AQS中的acquire()方法會調(diào)用AQS中的acquireQueued()方法讓線程在等待隊列中排隊。這就是非公平鎖的整個流程。

到此這篇關于Java公平鎖與非公平鎖的核心原理講解的文章就介紹到這了,更多相關Java公平鎖 非公平鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • KotlinScript構建SpringBootStarter保姆級教程

    KotlinScript構建SpringBootStarter保姆級教程

    這篇文章主要為大家介紹了KotlinScript構建SpringBootStarter的保姆級教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • SpringBoot JPA使用配置過程詳解

    SpringBoot JPA使用配置過程詳解

    這篇文章主要介紹了SpringBoot JPA使用配置過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • SpringBoot+Mybatis項目使用Redis做Mybatis的二級緩存的方法

    SpringBoot+Mybatis項目使用Redis做Mybatis的二級緩存的方法

    本篇文章主要介紹了SpringBoot+Mybatis項目使用Redis做Mybatis的二級緩存的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Java?Validated?分組校驗的使用

    Java?Validated?分組校驗的使用

    這篇文章主要介紹了Java?Validated?分組校驗的使用,文章記錄所以在這里記錄下分組校驗注解@Validated的使用,具有一定的參考價值,需要的朋友可以參考一下
    2022-02-02
  • java反射的作用知識點總結

    java反射的作用知識點總結

    在本篇文章里小編給大家整理的是關于java反射的作用知識點總結,需要的朋友們可以學習下。
    2020-02-02
  • 員工管理系統(tǒng)java版

    員工管理系統(tǒng)java版

    這篇文章主要為大家詳細介紹了java版的員工管理系統(tǒng),,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 使用springboot配置文件yml中的map形式

    使用springboot配置文件yml中的map形式

    這篇文章主要介紹了springboot配置文件yml中的map形式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Mybatis-Plus之ID自動增長的設置實現(xiàn)

    Mybatis-Plus之ID自動增長的設置實現(xiàn)

    本文主要介紹了Mybatis-Plus之ID自動增長的設置實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • Gradle快速安裝及入門

    Gradle快速安裝及入門

    今天小編就為大家分享一篇關于Gradle快速安裝及入門,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • java發(fā)起http請求調(diào)用post與get接口的方法實例

    java發(fā)起http請求調(diào)用post與get接口的方法實例

    在實際開發(fā)過程中,我們經(jīng)常需要調(diào)用對方提供的接口或測試自己寫的接口是否合適,下面這篇文章主要給大家介紹了關于java發(fā)起http請求調(diào)用post與get接口的相關資料,需要的朋友可以參考下
    2022-08-08

最新評論

白朗县| 昌黎县| 邳州市| 渭南市| 红安县| 钟山县| 揭阳市| 光山县| 宜城市| 桂林市| 尉氏县| 邵武市| 沈阳市| 措美县| 怀集县| 禹城市| 农安县| 凤翔县| 西峡县| 乌兰察布市| 平顶山市| 阿巴嘎旗| 特克斯县| 和平县| 安远县| 策勒县| 武定县| 金湖县| 勃利县| 久治县| 呈贡县| 乾安县| 太白县| 香河县| 慈利县| 泾阳县| 内丘县| 界首市| 娱乐| 峡江县| 璧山县|