欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

Lock鎖接口方法

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

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

公平鎖簡介

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

ReentranLock的公平鎖

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

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

在上述構造方法中,新建鎖對象是否為公平鎖,在于傳入的參數(shù)是true還是false,在三目運算符中,如果傳入參數(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é)點,如果沒有就會調用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的公平鎖,當線程調用ReentranLock類中的lock()方法時,會首先調用FairSync類中的lock()方法;然后FairSync類中的lock()方法會調用AQS類(AbstractQueuedSynchronizer)中的acquire(1)方法獲取資源,前面的文章里也提到過,acquire()方法會調用tryAcquire()方法嘗試獲取鎖,tryAcquire()方法里面沒有具體的實現(xiàn),tryAcquire()方法具體邏輯是由其子類實現(xiàn)的,因此調用的還是FairSync類中的方法。在AQS中的acquire()方法中如果嘗試獲取資源失敗,會調用addWaiter()方法將當前線程封裝為Node節(jié)點放到等待隊列的尾部,并且調用AQS中的acquireQueued方法使線程在等待隊列中排隊。

ReentranLock的非公平鎖

非公平鎖就是所有搶占鎖的線程都是不公平的,在我們日常生活中就相當于是插隊現(xiàn)象,不過也與插隊稍微不同。在多線程并發(fā)時,每個線程在搶占鎖的過程中,都會先嘗試獲取鎖,如果獲取成功,則直接指向具體的業(yè)務邏輯;如果獲取鎖失敗,則會像公平鎖一樣在等待隊列隊尾等待。

在非公平鎖模式下,由于剛來的線程可以在隊首位置進行一次插隊,所以當插隊成功時,后面的線程可能會出現(xià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è)務;如果獲取鎖資源失敗,則調用AQS中的acquire方法獲取資源,而acquire()方法會回調上面NonfairSyn類中的tryAcquire()方法,然后又會回調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),并調用setExclusiveOwnerThread(current)方法讓當前線程拿到鎖。

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

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

相關文章

  • java中構造器內部調用構造器實例詳解

    java中構造器內部調用構造器實例詳解

    在本篇文章里小編給大家分享的是關于java中構造器內部調用構造器實例內容,需要的朋友們可以學習下。
    2020-05-05
  • 淺談Maven Wrapper

    淺談Maven Wrapper

    這篇文章主要介紹了淺談Maven Wrapper,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • spring?boot微服務場景下apollo加載過程解析

    spring?boot微服務場景下apollo加載過程解析

    apollo?是一個開源的配置中心項目,功能很強大,apollo?本身的配置項并不復雜,但是因為配置的路徑特別多,非常容易搞混了,?所以本文試圖聚焦?spring-boot?的場景,在?spring-boot?微服務場景下,搞清楚?apollo-client的加載過程
    2022-02-02
  • 詳解Springboot對多線程的支持

    詳解Springboot對多線程的支持

    Spring是通過任務執(zhí)行器(TaskExecutor)來實現(xiàn)多線程和并發(fā)編程,使用ThreadPoolTaskExecutor來創(chuàng)建一個基于線城池的TaskExecutor。這篇文章給大家介紹Springboot對多線程的支持,感興趣的朋友一起看看吧
    2018-07-07
  • 單例模式 分析代碼優(yōu)化方法

    單例模式 分析代碼優(yōu)化方法

    這篇文章主要介紹了單例模式 分析代碼優(yōu)化方法,需要的朋友可以參考下
    2015-04-04
  • spring框架學習總結

    spring框架學習總結

    Spring是于2003 年興起的一個輕量級的Java 開發(fā)框架,由Rod Johnson創(chuàng)建。簡單來說,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架
    2021-06-06
  • Java設計模式開發(fā)中使用觀察者模式的實例教程

    Java設計模式開發(fā)中使用觀察者模式的實例教程

    這篇文章主要介紹了Java設計模式開發(fā)中使用觀察者模式的實例教程,松耦合和邏輯清晰的消息監(jiān)聽是觀察者模式的大特色,需要的朋友可以參考下
    2016-04-04
  • 線程池之newCachedThreadPool可緩存線程池的實例

    線程池之newCachedThreadPool可緩存線程池的實例

    這篇文章主要介紹了線程池之newCachedThreadPool可緩存線程池的實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Spring如何替換掉默認common-logging.jar

    Spring如何替換掉默認common-logging.jar

    這篇文章主要介紹了Spring如何替換掉默認common-logging.jar,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • 解讀maven項目中Tomcat10與JSTL的問題匯總(Debug親身經歷)

    解讀maven項目中Tomcat10與JSTL的問題匯總(Debug親身經歷)

    這篇文章主要介紹了解讀maven項目中Tomcat10與JSTL的問題匯總(Debug親身經歷),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評論