亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java多線程并發之ReentrantLock怎么使用

發布時間:2023-04-26 16:02:44 來源:億速云 閱讀:88 作者:iii 欄目:開發技術

本篇內容主要講解“Java多線程并發之ReentrantLock怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java多線程并發之ReentrantLock怎么使用”吧!

    ReentrantLock

    公平鎖和非公平鎖

    這個類是接口 Lock的實現類,也是悲觀鎖的一種,但是它提供了 lockunlock方法用于主動進行鎖的加和拆。在之前使用的 sychronized關鍵字是隱式加鎖機制,而它是顯示加鎖,同時,這個類的構造方法提供了公平和非公平的兩種機制。

    什么是公平和非公平呢?就是多線程對共享資源進行爭奪的時候,會出現一個線程或幾個線程完全占有共享資源,使得某些線程在長時間處于等待狀態。公平就是要等待時間過長的線程先獲得鎖。

    而在 ReentrantLock類中,提供了公平鎖和非公平鎖的使用。

    ReentrantLock源碼中,構造器提供了一個參數入口,

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

    當fair為true的時候,會創造一個 FairSync對象給 sync屬性,FairSync是繼承自 Sync的類,其中有一個 Lock方法,而在 ReentrantLock的Lcok中使用的是 sync屬性的 Lock方法,故能夠保證“公平”。

    使用非公平鎖就不需要在構造器中傳參數。

    在使用的時候,需要手動上鎖和解鎖。

    使用公平鎖,會將占優勢的線程進行限制,恢復掛起的線程,但是這個過程在CPU層面來講,是存在明顯時間差異的,非公平鎖的執行效率相對更高,所以一般來說不建議使用公平鎖,除非現實業務上需要符合實際需求。

    重入鎖

    ReentrantLock本身還支持重入的功能。

    重入鎖(Reentrant Lock)是一種支持重入的獨占鎖,它允許線程多次獲取同一個鎖,在釋放鎖之前必須相應地多次釋放鎖。重入鎖通常由兩個操作組成:上鎖(lock)和解鎖(unlock)。當一個線程獲取了重入鎖后,可以再次獲取該鎖而不被阻塞,同時必須通過相同數量的解鎖操作來釋放鎖。

    重入鎖具有如下特點:

    • 重入性:重入鎖允許同一個線程多次獲取同一把鎖,避免了死鎖的發生。

    • 獨占性:與公平鎖和非公平鎖一樣,重入鎖也是一種獨占鎖,同一時刻只能有一個線程持有該鎖。

    • 可中斷性:重入鎖支持在等待鎖的過程中中斷該線程的執行。

    • 條件變量:在使用 java.util.concurrent.locks.Condition 類配合重入鎖實現等待/通知機制時,等待狀態總是與重入鎖相關聯的。

    重入鎖相對于 synchronized 關鍵字的優勢在于,重入鎖具有更高的靈活性和擴展性,支持公平鎖和非公平鎖、可中斷鎖和可輪詢鎖等特性,能夠更好地滿足多線程環境下的并發控制需要。synchroized也有重入性。

    ReentrantLock lock = new ReentrantLock(true);
    public void get(){
        while(true){
            try{
                lock.lock();
                lock.lock();
            }catch(Exception exception){
    
            }finally{
                lock.unlock();
                lock.unlock();
            }
        }
    }

    可重入的前提 lock是同一個對象,而關鍵字 synchroized的 Monitor也是同一個對象充當,才能判定為重入。

    public void get(){
        while(true){
            synchronized(this){
                System.out.println("外層");
                synchronized(this){
                    System.out.println("內層");
                }
            }
        }
    }

    那么Java是怎么檢測鎖的重入和獲取鎖的次數的呢?在之前說過的 ObjectMobitor的C++源代碼中有 _recursions和_count來記錄鎖的重入次數和線程獲取鎖的次數。這樣在Java層面就表示一個鎖對象都擁有一個鎖計數器 _count和一個指向持有這個鎖的線程的指針 _owner只有當前持有鎖的線程才能使得計數器+1,其他線程只有等待鎖被釋放(計數器置0)才能持有并+1。

    在源碼中,非公平鎖的lock方法如下:

    //ReentrantLock類中:
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    //0的參數為是expect,是期望值,而1是update,是更新值

    在執行comparaAndSetState方法的時候,它會詢問鎖的計數器(在底層執行compareAndSwapInt的本地方法),并期望數值為0,如果為0返回true,然后設置執行線程主是當前線程。如果非0,那么他就會執行acquire

    //AbstractQueuedSynchronizer類中:
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    //這里的tryAcquire,需要在其繼承的子類中進一步實現對應的功能
    //子類可以根據自己的需要重新定義tryAcquire(int arg)的實現方式,從而實現更優秀的鎖控制方案:
    //而在其子類FairSync中便覆蓋了這個方法
    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

    將線程放入等待隊列。

    同時計數器是通過 unlock來-1,所以 lock和unlock次數不匹配就會產生死鎖,也就是當兩個線程調用同一個 ReentrantLock如果一個線程中的上鎖解鎖次數不相等,那么計數器沒有被清零,當另一個線程請求鎖的時候,看到鎖計數器不是0,就認為被的線程仍然持有它,所以一直等待它被釋放。需要了解底層的可以去看AQS中的release方法。

    而在 ReentrantLock中有一個抽象內部類 Sync,它繼承自抽象類AbstractQueuedSynchronizer(簡稱AQS),這個類中有一個內部 Node類,當有線程等待這把鎖的時候,會創建一個等待隊列,放置這些處于等待的線程。(AQS實現比較復雜,有興趣可以看看“竹子愛熊貓”大佬的文章。)

    小結

    ReentrantLock類中,有內部類三個,Sync,FairSync,NonfairSync,他們的關系是Sync是后兩個的父類,后兩個是兄弟類,同時Sync繼承自AQS類,在AQS中有很多實現公平和非公平、可重入的機制,而具體實現效果的是Sync,FairSync,NonfairSync

    疑惑

    在下列代碼中,為什么在第一個線程的最后加上.join(),沒有使得線程阻塞,而沒有它就會阻塞?

    Lock lock = new ReentrantLock();
    new CompletableFuture().runAsync(() -> {
        lock.lock();
        try{
            System.out.println(1);
            TimeUnit.SECONDS.sleep(2);
        }catch(Exception e){
        }finally{
    }});
    //上面加上.join()
    new CompletableFuture().runAsync(() -> {
        lock.lock();
        try{
            System.out.println(2);
        }catch(Exception e){
        }finally{
            lock.unlock();
    }}).join();

    到此,相信大家對“Java多線程并發之ReentrantLock怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    鹤岗市| 巴南区| 江孜县| 冀州市| 田阳县| 织金县| 汉川市| 伊春市| 仁化县| 六安市| 二连浩特市| 吉木萨尔县| 府谷县| 武义县| 万宁市| 乌海市| 武宁县| 江川县| 辛集市| 鹤山市| 长阳| 澄城县| 灵寿县| 靖江市| 株洲县| 天门市| 巫溪县| 凤凰县| 定陶县| 于都县| 万安县| 和平区| 新晃| 佛山市| 敖汉旗| 竹北市| 湘潭县| 抚远县| 巴中市| 景德镇市| 咸阳市|