国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

ReentrantLock 性能好在哪里?

開發(fā)
ReentrantLock作為最常用的獨占鎖,其內(nèi)部就是包含了AQS的子類實現(xiàn)了線程搶鎖和釋放鎖的邏輯。

先了解一下

我們知道實現(xiàn)一把鎖要有如下幾個邏輯:

  • 鎖的標(biāo)識
  • 線程搶鎖的邏輯
  • 線程掛起的邏輯
  • 線程存儲邏輯
  • 線程釋放鎖的邏輯
  • 線程喚醒的邏輯

我們在講解AQS的時候說過AQS基本負(fù)責(zé)了實現(xiàn)鎖的全部邏輯,唯獨線程搶鎖和線程釋放鎖的邏輯是交給子類來實現(xiàn)了,而ReentrantLock作為最常用的獨占鎖,其內(nèi)部就是包含了AQS的子類實現(xiàn)了線程搶鎖和釋放鎖的邏輯。

我們在使用ReentrantLock的時候一般只會使用如下方法:

 ReentrantLock lock=new ReentrantLock();
 lock.lock();
 lock.unlock();
 lock.tryLock();
 Condition condition=lock.newCondition();
 condition.await();
 condition.signal();
 condition.signalAll();     

技術(shù)架構(gòu)

如果我們自己來實現(xiàn)一個鎖,那么如何設(shè)計呢?

根據(jù)AQS的邏輯,我們寫一個子類sync,這個類一定會調(diào)用父類的acquire方法進(jìn)行上鎖,同時重寫tryAcquire方法實現(xiàn)自己搶鎖邏輯,也一定會調(diào)用release方法進(jìn)行解鎖,同時重寫tryRelease方法實現(xiàn)釋放鎖邏輯。

那么ReentrantLock是怎么實現(xiàn)的呢?

ReentrantLock的實現(xiàn)的類架構(gòu)如下,ReentrantLock對外提供作為一把鎖應(yīng)該具備的api,比如lock加鎖,unlock解鎖等等,而它內(nèi)部真正的實現(xiàn)是通過靜態(tài)內(nèi)部類sync實現(xiàn),sync是AQS的子類,是真正的鎖,因為這把鎖需要支持公平和非公平的特性,所以sync又有兩個子類FairSync和NonfairSync分別實現(xiàn)公平鎖和非公平鎖。

因為是否公平說的是搶鎖的時候是否公平,那兩個子類就要在上鎖方法acquire的調(diào)用和搶鎖方法tryAcquire的重寫上做文章。

公平鎖做了什么文章?

 static final class FairSync extends Sync {
  
        final void lock() {
            acquire(1);
        }

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

公平鎖比較簡單,直接調(diào)用了父級類AQS的acquire方法,因為AQS的鎖默認(rèn)就是公平的排隊策略。

重寫tryAcquire方法的邏輯為:

  • 判斷當(dāng)前鎖是否被占用,即state是否為0
  • 如果當(dāng)前鎖沒有被占用,然后會判斷等待隊列中是否有線程在阻塞等待,如果有,那就終止搶鎖,如果沒有,就通過cas搶鎖,搶到鎖返回true,沒有搶到鎖返回false。
  • 如果當(dāng)前鎖已經(jīng)被占用,然后判斷占用鎖的線程是不是自己,如果是,就會將state加1,表示重入,返回true。如果不是自己那就是代表沒有搶到鎖,返回false。

公平就公平在老老實實排隊。

非公平鎖做了什么文章?

  static final class NonfairSync extends Sync {
      
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    
    //nonfairTryAcquire代碼在父類sync里面
     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;
        }

非公平鎖也很簡單,沒有直接調(diào)用了父級類AQS的acquire方法,而是先通過cas搶鎖,它不管等待隊列中有沒有其他線程在排隊,直接搶鎖,這就體現(xiàn)了不公平。

它重寫tryAcquire方法的邏輯為:

  • 判斷當(dāng)前鎖是否被占用,即state是否為0
  • 如果當(dāng)前鎖沒有被占用,就直接通過cas搶鎖(不管等待隊列中有沒有線程在排隊),搶到鎖返回true,沒有搶到鎖返回false。
  • 如果當(dāng)前鎖已經(jīng)被占用,然后判斷占用鎖的線程是不是自己,如果是,就會將state加1,表示重入,返回true。如果不是自己那就是代表沒有搶到鎖,返回false。

公平鎖和非公平分別重寫了tryAcquire方法,來滿足公平和非公平的特性。那么tryAcquire方法也是需要子類重寫的,因為它和是否公平無關(guān),因此tryAcquire方法被抽象到sync類中重寫。

sync類中
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

釋放鎖的邏輯如下:

  • 獲取state的值,然后減1
  • 如果state為0,代表鎖已經(jīng)釋放,清空aqs中的持有鎖的線程字段的值
  • 如果state不為0,說明當(dāng)前線程重入了,還需要再次釋放鎖
  • 將state寫回

釋放鎖往往和搶鎖邏輯是對應(yīng)的,每個子類搶鎖邏輯不同的話,釋放鎖的邏輯也會對應(yīng)不同。

具體實現(xiàn)

接下來我們通過ReentrantLock的使用看下它的源碼實現(xiàn)

class X {
            private final ReentrantLock lock = new ReentrantLock();
            Condition condition1=lock.newCondition();
            Condition condition2=lock.newCondition();
            public void m() {
                lock.lock();
                try {

                    if(條件1){
                        condition1.await();
                    }
                    if(條件2){
                        condition2.await();
                    }
                } catch (InterruptedException e) {

                } finally {
                    condition1.signal();
                    condition2.signal();
                    lock.unlock();
                }
            }
        }

1.先看這個方法:lock.lock()

ReentrantLock類
public void lock() {
        sync.lock();
    }
  NonfairSync 類中
  final void lock() {
    if (compareAndSetState(0, 1))
    setExclusiveOwnerThread(Thread.currentThread());
    else
      acquire(1);
  }
  FairSync 類中
  final void lock() {
      acquire(1);
  }     

公平鎖和非公平鎖中都實現(xiàn)了lock方法,公平鎖直接調(diào)用AQS的acquire,而非公平鎖先搶鎖,搶不到鎖再調(diào)用AQS的acquire方法進(jìn)行上鎖

進(jìn)入acquire方法后的邏輯我們就都知道了。

2.再看這個方法lock.unlock()

public void unlock() {
        sync.release(1);
}

unlock方法內(nèi)直接調(diào)用了AQS的Release方法進(jìn)行解鎖的邏輯,進(jìn)入release方法后邏輯我們都已經(jīng)知道了,這里不再往下跟。

3.最后看這個方法lock.tryLock()

  public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

tryLock方法直接調(diào)用sync的tryAcquireNanos方法,看過AQS的應(yīng)該知道tryAcquireNanos這個方法是父類AQS的方法,這個方法和AQS中的四個核心方法中的Acquire方法一樣都是上鎖的方法,無非是上鎖的那幾個步驟,調(diào)用tryAcquire方法嘗試搶鎖,搶不到鎖就會進(jìn)入doAcquireNanos方法。

 public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }

doAcquireNanos這個方法做的其實就是入隊,阻塞等一系列上鎖操作,邏輯和Acquire方法中差不多,但是有兩點不同:

  • 該方法支持阻塞指定時長。
  • 該方法支持中斷拋異常。

看下下面的代碼

  private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

這里的阻塞不再是LockSupport類的park方法,而是parkNanos方法,這個方法支持指定時長的阻塞,AQS正是利用這個方法實現(xiàn)阻塞指定時長,當(dāng)自動喚醒后,循環(huán)中會判斷是否超過設(shè)定時長,如果超過直接返回false跳出循環(huán)。

在阻塞期間,如果線程被中斷,就會拋出異常,同樣會跳出循環(huán),外面可以通過捕獲這個異常達(dá)到中斷阻塞的目的。

可見ReentrantLock其實啥也沒做,其tryLock方法完全是依賴AQS實現(xiàn)。

4.lock.newCondition();

在AQS那篇我們說過Condition是AQS中的條件隊列,可以按條件將一批線程由不可喚醒變?yōu)榭蓡拘选?/p>

ReentrantLock類
 public Condition newCondition() {
        return sync.newCondition();
 }
sync靜態(tài)內(nèi)部類
final ConditionObject newCondition() {
            return new ConditionObject();
}

sync提供了創(chuàng)建Condition對象的方法,意味著ReentrantLock也擁有Condition的能力。

ReentrantLock和synchronized對比

我們下面說的ReentrantLock其實就是說AQS,因為它的同步實現(xiàn)主要在AQS里面。

1.實現(xiàn)方面

ReentrantLock是jdk級別實現(xiàn)的,其源碼在jdk源碼中可以查看,沒有脫離java。synchronized是jvm級別實現(xiàn)的,synchronized只是java端的一個關(guān)鍵字,具體邏輯實現(xiàn)都在jvm中。

2.性能方面

優(yōu)化前的synchronized性能很差,主要表現(xiàn)在兩個方面:因為大多數(shù)情況下對于資源的爭奪并沒有那么激烈,甚至于某個時刻可能只有一個線程在工作,在這種沒有競爭或者競爭壓力很小的情況下,如果每個線程都要進(jìn)行用戶態(tài)到內(nèi)核態(tài)的切換其實是很耗時的。

jdk1.6對synchronized底層實現(xiàn)做了優(yōu)化,優(yōu)化后,在單線程以及并發(fā)不是很高的情況下通過無鎖偏向和自旋鎖的方式避免用戶態(tài)到內(nèi)核態(tài)的切換,因此性能提高了,優(yōu)化后的synchronized和ReentrantLock性能差不多了。

ReentrantLock是在jdk實現(xiàn)的,它申請互斥量就是對鎖標(biāo)識state的爭奪,它是通過cas方式在java端實現(xiàn)。

對于爭奪不到資源的線程依然要阻塞掛起,但凡阻塞掛起都要依賴于操作系統(tǒng)底層,這一步的用戶態(tài)到內(nèi)核態(tài)的切換是避免不了的。

因此在單線程進(jìn)入代碼塊的時候,效率是很高的,因此我們說ReentrantLock性能高于原始的synchronized

  • 申請互斥量:synchronized的鎖其實就是爭奪Monitor鎖的擁有權(quán),這個爭奪過程是通過操作系統(tǒng)底層的互斥原語Mutex實現(xiàn)的,這個過程會有用戶態(tài)到內(nèi)核態(tài)的切換。
  • 線程阻塞掛起:沒能搶到到Monitor鎖擁有權(quán)的線程要阻塞掛起,阻塞掛起這個動作也是依靠操作系統(tǒng)實現(xiàn)的,這個過程也需要用戶態(tài)到內(nèi)核態(tài)的切換。

3.特性方面

兩個都是常用的典型的獨占鎖。ReentrantLock可重入,可中斷,支持公平和非公平鎖,可嘗試獲取鎖,可以支持分組將線程由不可喚醒變?yōu)榭蓡拘选?/p>

synchronized可重入,不可中斷,非公平鎖,不可嘗試獲取鎖,只支持一個或者全部線程由不可喚醒到可喚醒。

4.使用方面

synchronized不需要手動釋放鎖,ReentrantLock需要手動釋放鎖,需要考慮異常對釋放鎖的影響避免異常導(dǎo)致線程一直持有鎖。

以下是兩個鎖的使用方式

class X {
            private final ReentrantLock lock = new ReentrantLock();
            Condition condition1=lock.newCondition();
            Condition condition2=lock.newCondition();
            public void m() {
                lock.lock();
                try {

                    if(1==2){
                        condition1.await();
                    }
                    if(1==3){
                        condition2.await();
                    }
                } catch (InterruptedException e) {

                } finally {
                    condition1.signal();
                    condition2.signal();
                    lock.unlock();
                }
            }
        }
   class X {
            private final testtest sync=new testtest();;
            public void m() throws InterruptedException {
                synchronized(sync){
                    if(1==2){
                        sync.wait();
                    }
                    sync.notify();
                    sync.notifyAll();
                }
            }
        }

對比代碼及特性說明:

  • 兩個鎖都是依賴一個對象:lock和sync
  • condition和wait方法具有同樣的效果,進(jìn)入condition和wait的線程將陷入等待(不可喚醒狀態(tài)),只有被分別調(diào)用signal和notify方法線程才會重新變?yōu)榭蓡拘褷顟B(tài),請注意是可喚醒,而不是被喚醒。
  • 可喚醒是說具備了競爭資源的資格,資源空閑后,synchronized中會在可喚醒狀態(tài)的線程中隨機(jī)挑選一個線程去拿鎖,而ReentrantLock中不可喚醒的線程變?yōu)榭蓡拘褷顟B(tài),其實就是將條件隊列中的線程搬到等待隊列中排隊,只有隊頭的才會去嘗試拿鎖。
  • ReentrantLock分批將線程由不可喚醒變?yōu)榭蓡拘岩苍谶@段代碼中體現(xiàn)了,代碼中按照不同的條件將線程放入不同的condition,每個condition就是一個組,釋放的時候也可以按照不同的條件進(jìn)行釋放。而synchronized中進(jìn)入wait的線程不能分組,釋放也只能隨機(jī)釋放一個或者全部釋放。
責(zé)任編輯:趙寧寧 來源: 碼農(nóng)本農(nóng)
相關(guān)推薦

2024-09-03 08:06:30

AQS線程代碼

2018-01-23 11:42:50

程序員編程代碼

2019-05-05 10:31:53

5G 4G無線

2021-05-12 08:47:54

Go數(shù)組切片

2022-07-27 14:53:51

Windows 11微軟游戲

2018-08-16 18:38:00

外設(shè)

2014-06-20 16:19:08

802.11ac802.11n

2009-01-09 23:06:41

服務(wù)器SCSI硬盤PC

2009-06-23 09:07:38

2010-11-11 17:15:13

SQL Server視

2011-11-08 10:15:47

Scala

2023-09-22 09:00:00

云計算

2021-03-12 08:56:25

電腦裝機(jī)軟件Edge瀏覽器

2024-03-29 12:06:31

云服務(wù)企業(yè)

2018-08-20 15:00:32

Linux深度操作系統(tǒng)發(fā)行版

2018-08-31 08:51:31

C 語言開發(fā)編程

2018-11-26 15:04:49

SDN網(wǎng)絡(luò)數(shù)據(jù)中心

2021-01-25 14:39:19

新基建

2020-09-27 16:15:42

新基建5G人工智能

2021-02-01 10:46:32

多云云安全云計算
點贊
收藏

51CTO技術(shù)棧公眾號

26uuu国产在线精品一区二区| 99久久精品国产观看| 尤物yw午夜国产精品视频明星| 4480yy私人影院高清不卡| 99re8在线精品视频免费播放| 亚洲精品成人三区| 中文亚洲免费| 蜜桃999成人看片在线观看| 9191国语精品高清在线| 国产精品久久久久久久一区探花| 91精品短视频| 欧美成人一区二区三区电影| 欧美日韩国产网站| 色久欧美在线视频观看| 麻豆久久久久| 欧美大尺度在线观看| www.久久久.com| 另类少妇人与禽zozz0性伦| 四虎影视精品永久在线观看| 插插插亚洲综合网| 亚洲老司机网| 欧美激情中文字幕在线| 国产精品调教| 国产精品黄页免费高清在线观看| 天堂在线精品| 91精品免费看| 国产精品一二| 一区二区三视频| 91在线porny国产在线看| 亚洲这里只有精品| 亚洲精品日韩专区silk| 在线免费日韩| 欧美一区二区女人| 九九色在线视频| 久久亚洲国产成人| 欧美美女在线| 99精品欧美一区二区三区| 最新亚洲激情| 18视频在线观看娇喘| 26uuuu精品一区二区| 男女激情视频网站| 欧美性猛交xxxx乱大交退制版| 手机在线免费看av| 综合国产在线视频| 久久九九热re6这里有精品| 国产精品电影在线观看| 欧美黄色免费| 青青草影院在线观看| 国产丝袜美腿一区二区三区| 色网址在线观看| 精品久久人人做人人爽| 91麻豆精品| 亚洲www在线观看| 久久超级碰视频| 亚洲成色www.777999| 亚洲成年人网站在线观看| 成人午夜在线影视| 欧美老女人性生活| 欧美日韩影院| 免费国产a级片| 精品国产31久久久久久| aaa在线播放视频| 啊v视频在线一区二区三区| 精品国产一区二区三区久久久蜜臀| 国产成人亚洲欧美| 成人高清免费观看| 麻豆国产在线播放| 精品国产自在精品国产浪潮| 99久久国产综合精品成人影院| 日本一区二区三区精品视频| 久久婷婷国产综合精品青草| 日韩在线无毛| 精品国产一区二区三区久久| 91精品国产乱码久久久久久久| 大桥未久一区二区三区| 午夜不卡av免费| 69堂精品视频在线播放| 95av在线视频| 国产亚洲欧美中文| 污视频网站免费在线观看| 欧美孕妇与黑人孕交| 欧美aⅴ一区二区三区视频| caoporen人人| 亚洲第一偷拍网| 婷婷精品进入| 成人免费xxxxx在线视频| 日韩一级免费一区| 欧美亚洲精品在线| www精品久久| 欧美一区二区三区人| 欧美人与拘性视交免费看| 亚洲国产精品无码观看久久| 欧美日韩一区二区电影| 欧美wwwwww| 国产 日韩 欧美在线| 欧美一级高清片| 欧美电影免费观看高清| 精品视频一区二区在线| 欧美岛国在线观看| 欧美国产激情| www污污在线| 欧美与黑人午夜性猛交久久久| 成人精品免费看| 嗯~啊~轻一点视频日本在线观看| 亚洲xxx自由成熟| 亚洲精品乱码久久久久久久久 | 国产精品一区二区免费| 日本一区二区成人| 日韩大陆av| www.av片| 国产亚洲成av人片在线观看桃| 久久久久久黄| 黄色在线播放网站| www日韩av| 欧美在线不卡一区| 韩国亚洲精品| 99中文字幕一区| 亚洲午夜精品一区 二区 三区| 国产精品夜夜夜爽张柏芝| 色妞www精品视频| 成人免费av| а√最新版地址在线天堂| 91精品国产91久久久| 国产三级精品在线| h视频久久久| 国产一级特黄a大片免费| 久久精品国产综合| 99国内精品久久| 国产69精品久久| jizzjizzxxxx| 色综合久久悠悠| 国产精品久久久久久久久果冻传媒 | 中文字幕欧美专区| 久久 天天综合| 九九精品调教| 男人添女人下部视频免费| 中文一区二区视频| 99精品国产一区二区三区不卡| 欧美视频第一| 精品一区二区中文字幕| 欧美日韩国产第一页| 中文字幕在线视频一区| 亚洲精品中文字幕99999| 午夜3点看的视频| 成人a级免费视频| 欧美日韩中文字幕一区二区| 国产亚洲网站| 亚洲天堂手机| 777久久久精品一区二区三区| 欧美大片在线看| 午夜影院在线观看欧美| 亚洲成人资源| 亚洲女色av| 亚洲免费一级视频| 91天堂在线观看| 日韩精品专区在线影院重磅| 成人午夜视频在线观看| 日韩av中文字幕一区| 黄色片在线免费看| 日本福利视频导航| 午夜精品久久久久久久白皮肤| 岛国av一区二区三区| 久久精品在线| 成人污版视频| 天堂av中文在线资源库| 水蜜桃一区二区三区| 日韩视频第一页| 亚洲成人1区2区| 久久国产精品99精品国产| 欧美一区在线观看视频| 日韩av地址| 日韩精品手机在线观看| 97超视频免费观看| 欧美一区二区三区成人| 成人午夜精品一区二区三区| 国产精品免费不| 国产三级电影在线播放| 麻豆一区二区三区四区精品蜜桃| 久久国产精品99久久久久久丝袜| 少妇高潮久久77777| 五月婷婷激情综合| 麻豆成人综合网| 中国av一区| 18video性欧美19sex高清| 欧美 日韩 国产 激情| 激情久久av| 久久久久久久香蕉网| 欧美老女人第四色| 国产精品三级在线观看| 亚洲自拍另类| 伦理一区二区| 美女尤物在线视频| 欧美aaa大片| 四虎精品欧美一区二区免费| 国产精品丝袜一区二区三区| 亚洲色图av在线| 欧美在线啊v一区| 国产精品久久久久永久免费观看 | 亚洲第一二三区| 亚洲妇女成熟|