国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

AbstractQueuedSynchronizer原理剖析

vslam / 3551人閱讀

摘要:無(wú)論是公平鎖還是非公平鎖,它們的實(shí)現(xiàn)都依賴(lài)于,它提供了一個(gè)基于先進(jìn)先出等待隊(duì)列實(shí)現(xiàn)和的框架。特性如下僅通過(guò)一個(gè)類(lèi)型來(lái)代表狀態(tài)。等喚醒的時(shí)候,重新獲取鎖,并清掉中的線(xiàn)程。

無(wú)論是公平鎖還是非公平鎖,它們的實(shí)現(xiàn)都依賴(lài)于AbstractQueuedSynchronizer,它提供了一個(gè)基于先進(jìn)先出等待隊(duì)列 實(shí)現(xiàn)block locks和synchronizers的框架。特性如下

僅通過(guò)一個(gè) int 類(lèi)型來(lái)代表狀態(tài)。對(duì)于ReentrantLock而言,他就是線(xiàn)程持有鎖的次數(shù),當(dāng)次數(shù)為0時(shí),代表鎖沒(méi)有被持有,正數(shù)代表被持有的次數(shù),負(fù)數(shù)則是超出了鎖的持有范圍,有可能存在死循環(huán)

支持獨(dú)占模式(默認(rèn)的)和共享模式。在獨(dú)占模式中,去獲取一個(gè)已經(jīng)被其它線(xiàn)程擁有的鎖只會(huì)失敗,共享模式中,則多個(gè)線(xiàn)程是可以成功的。

lock()原理

當(dāng)ReentrantLock獲取鎖失敗時(shí),會(huì)執(zhí)行 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)

private Node addWaiter(Node mode) { 
    Node node = new Node(Thread.currentThread(), mode); //創(chuàng)建一個(gè)節(jié)點(diǎn),存儲(chǔ)當(dāng)前的線(xiàn)程,以及鎖持有的模式,對(duì)于 ReentrantLock來(lái)說(shuō)就是 獨(dú)占 型
    // Try the fast path of enq; backup to full enq on failure    
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {//CAS操作,如果當(dāng)前的尾部節(jié)點(diǎn)沒(méi)有被其它線(xiàn)程更改,那么把新的節(jié)點(diǎn)設(shè)置成隊(duì)列的尾部
            pred.next = node;
            return node;
        }
    }
    enq(node);//首次入隊(duì)
    return node;
}

獲取失敗進(jìn)行入隊(duì)操作,首先就是往隊(duì)列中添加一個(gè)正在等待的節(jié)點(diǎn)Node


從Node本身的結(jié)構(gòu)可以看到,AQS(AbstractQueuedSynchronizer)本身就維護(hù)了一個(gè)雙向鏈表,用來(lái)存放等待中的線(xiàn)程。鏈表的每個(gè)節(jié)點(diǎn),代表那個(gè)線(xiàn)程,是獨(dú)占還是共享鎖。
創(chuàng)建好節(jié)點(diǎn)之后,便執(zhí)行入隊(duì)操作,對(duì)于首次創(chuàng)建隊(duì)列

private Node enq(final Node node) {
    for (;;) {
       //借助CAS機(jī)制實(shí)現(xiàn)無(wú)鎖操作,所以需要一直執(zhí)行直到CAS成功
        Node t = tail;
        if (t == null) { // 初始化發(fā)生在第一次創(chuàng)建隊(duì)列,這樣的好處是,當(dāng)競(jìng)爭(zhēng)不激烈的時(shí)候,實(shí)際上也就不會(huì)發(fā)生這些操作,性能也會(huì)好些
             if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

可以看到,入隊(duì)也就是從隊(duì)尾插入新的等待線(xiàn)程,入隊(duì)完畢,也就開(kāi)始去進(jìn)行不斷的嘗試,直到獲取鎖成功,可以看到,對(duì)于lock來(lái)說(shuō),其實(shí)已經(jīng)是阻塞了

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor(); //優(yōu)先執(zhí)行當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)
            if (p == head && tryAcquire(arg)) { //僅當(dāng)當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)是head,才去獲取線(xiàn)程,這里可以看出其實(shí)先等待的線(xiàn)程是會(huì)優(yōu)先處理,也就是FIFO原則
                setHead(node); 
                p.next = null; // help GC    ,釋放掉當(dāng)前線(xiàn)程在隊(duì)列中的引用,也可以看做’出隊(duì)"了            
                failed = false;
                //執(zhí)行到這里說(shuō)明獲取鎖成功
                return interrupted;
            }
            //執(zhí)行到這里說(shuō)明存在競(jìng)爭(zhēng),有多個(gè)線(xiàn)程都在等待一個(gè)鎖
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt()) //里面會(huì)對(duì)當(dāng)前線(xiàn)程執(zhí)行中斷,當(dāng)被喚醒時(shí),繼續(xù)循環(huán)
                    //如果線(xiàn)程被中斷,設(shè)置中斷標(biāo)記,區(qū)別于 doAcquireInterruptibly,doAcquireInterruptibly是直接拋出異常,這也就是 lockInterruptibly能夠拋出中斷的原因
                    interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
從這里可以看到,無(wú)論鎖是公平鎖還是非公平鎖,只要被放入了等待隊(duì)列,此時(shí)的執(zhí)行依然是誰(shuí)先等待就先執(zhí)行誰(shuí)  ,非公平鎖體現(xiàn)在新來(lái)的線(xiàn)程會(huì)無(wú)視已經(jīng)等了的線(xiàn)程,可以?xún)?yōu)先去搶鎖,所以公平體現(xiàn)在第一次參與搶鎖的線(xiàn)程會(huì)去等待已經(jīng)在等待隊(duì)列中的線(xiàn)程,非公平并不是說(shuō)從已經(jīng)在等待的線(xiàn)程隊(duì)列里面隨便選一個(gè)

shouldParkAfterFailedAcquire的源碼如下

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus; //查看前一個(gè)節(jié)點(diǎn)的等待狀態(tài)
    if (ws == Node.SIGNAL)
            //已經(jīng)嘗試過(guò)獲取鎖,可以執(zhí)行park了
            return true;
    if (ws > 0) {   
        do {
            //去掉隊(duì)列中所有已經(jīng)取消的線(xiàn)程
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {             
        //此時(shí)當(dāng)前線(xiàn)程的前一個(gè)節(jié)點(diǎn)的等待狀態(tài)必定是0或者PROGATE,這表明當(dāng)前線(xiàn)程在park之前可以再?lài)L試一次去獲取鎖,也就是說(shuō)前一個(gè)節(jié)點(diǎn)可能剛獲取到SIGNAL
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

waitStatus:等待的狀態(tài),共有5種

SIGNAL:,表明它的前一個(gè)節(jié)點(diǎn)需要執(zhí)行 unparking;

CANCELLED:當(dāng)前節(jié)點(diǎn)保存的線(xiàn)程由于超時(shí)或者中斷被取消了;

CONDITION:接檔正處于條件隊(duì)列中,執(zhí)行了await;

PROPAGATE:一個(gè)共享的鎖需要傳遞釋放信號(hào)到其它節(jié)點(diǎn)

0:非上述4中狀態(tài),有可能是剛獲取signal,此時(shí)它的值是0,也有可能是新建的head節(jié)點(diǎn)

parkAndCheckInterrupt主要是park當(dāng)前線(xiàn)程

private final boolean parkAndCheckInterrupt() {
    //當(dāng)獲取不到許可時(shí),阻塞線(xiàn)程,解除阻塞狀態(tài)的情況如下:
    //1 某個(gè)線(xiàn)程對(duì)這個(gè)線(xiàn)程調(diào)用了unpark方法
    //2 某個(gè)線(xiàn)程中斷了這個(gè)線(xiàn)程
    //3 這個(gè)方法毫無(wú)理由的返回了 [park比較奇特的地方],基于這樣,調(diào)用的時(shí)候必須去判斷park的條件,以及當(dāng)它返回的時(shí)候,去設(shè)置中斷的狀態(tài)
    LockSupport.park(this); 
    //返回線(xiàn)程的中斷狀態(tài)
    return Thread.interrupted();
}

至此lock()執(zhí)行結(jié)束

unlock()原理

當(dāng)執(zhí)行unlock時(shí),ReentrentLock執(zhí)行對(duì)應(yīng)的Release

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        //執(zhí)行這里表示所已經(jīng)被釋放,可以讓它的下一個(gè)節(jié)點(diǎn)來(lái)?yè)屾i
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h); //h.waitStatus == 0 表示還沒(méi)有執(zhí)行park,自然不需要unpark
        return true;
    }
    return false;
}

如果release成功,即當(dāng)前線(xiàn)程持有的所有鎖都已經(jīng)釋放,那么就可以執(zhí)行 unparkSuccessor,從源碼可以看到,unpark是從頭部開(kāi)始進(jìn)行的,結(jié)合lock的原理,可知AQS本身就是一個(gè)先進(jìn)先出的隊(duì)列
unparkSuccessor源碼如下

private void unparkSuccessor(Node node) {
     int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

     Node s = node.next; //有可能線(xiàn)程被取消了,所以從尾部往前遍歷,到最近一個(gè)沒(méi)有被取消的線(xiàn)程
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t; //確保線(xiàn)程沒(méi)有取消
    }
    if (s != null)
        LockSupport.unpark(s.thread); //恢復(fù)線(xiàn)程
}

至此unlock()完畢

await的原理
public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();//當(dāng)前線(xiàn)程已經(jīng)中斷了,拋出中斷異常
    //添加一個(gè)新的waiter到condition queue中,這個(gè)新的Node的waitStatus會(huì)被標(biāo)記為CONDITION
    Node node = addConditionWaiter(); 
    //釋放當(dāng)前線(xiàn)程擁有的鎖,即從sync queue中去掉當(dāng)前線(xiàn)程
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
    //如果當(dāng)前線(xiàn)程不在持有鎖的隊(duì)列里頭,對(duì)他進(jìn)行休眠,當(dāng)其它線(xiàn)程執(zhí)行 unlock的時(shí)候,釋放鎖,就會(huì)執(zhí)行unpark操作,此時(shí)它會(huì)被喚醒,喚醒后,如果它在syn隊(duì)列里頭,開(kāi)始繼續(xù)往下執(zhí)行。(這個(gè)插入操作則是由signal完成)
        LockSupport.park(this); 
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;//等待的過(guò)程中線(xiàn)程中斷了,退出
    }
//重新競(jìng)爭(zhēng)鎖,相當(dāng)于執(zhí)行了lock操作
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
    //再次去獲取鎖,如果當(dāng)前的線(xiàn)程在park的時(shí)候是被中斷了,并且ConditionObject并不是由于中斷返回,這里再次標(biāo)記為中斷
        interruptMode = REINTERRUPT;  
    if (node.nextWaiter != null) 
    //清除非Condition模式的線(xiàn)程,而在signal中有先關(guān)操作將conditon的線(xiàn)程設(shè)置成非condition
         unlinkCancelledWaiters();
    if (interruptMode != 0)
    //上報(bào)等待的過(guò)程中發(fā)生了中斷,如果是要拋出中斷,就拋出,否則再次執(zhí)行中斷
        reportInterruptAfterWait(interruptMode); 
}

isOnSyncQueue源碼如下

final boolean isOnSyncQueue(Node node) {
    if (node.waitStatus == Node.CONDITION || node.prev == null)
    //node本身是調(diào)用了 await 方法,或者沒(méi)有在獲取鎖的隊(duì)列里頭,[如果在里頭必定有一個(gè)前置的節(jié)點(diǎn)]
        return false; 
    if (node.next != null) 
    //當(dāng)前節(jié)點(diǎn)存在下一個(gè)節(jié)點(diǎn),那么它肯定是執(zhí)行過(guò) enq ,即獲取過(guò)鎖
        return true; 
    // CAS失敗的時(shí)候,有可能 node.rev是沒(méi)有的,因此需要從頭到尾遍歷一次
   return findNodeFromTail(node); 
}

checkInterruptWhileWaiting源碼如下

private int checkInterruptWhileWaiting(Node node) {
    return Thread.interrupted() ?
        (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
        0;
}
final boolean transferAfterCancelledWait(Node node) {
    if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
    //線(xiàn)程中斷重新獲取鎖,并且設(shè)置waitStatus為0,以便后續(xù)線(xiàn)程從condition queue清除
        enq(node); 
        return true;
    }
    while (!isOnSyncQueue(node))
    //如果CAS失敗,只要當(dāng)前節(jié)點(diǎn)沒(méi)有在Sync queue中,那么一直自旋,每次都會(huì)交出執(zhí)行權(quán)限
        Thread.yield(); 
    return false;
}

可以看到,await其實(shí)就是釋放線(xiàn)程原有的鎖,并把它放入conditon隊(duì)列中,然后執(zhí)行阻塞。等喚醒的時(shí)候,重新獲取鎖,并清掉condition queue中的線(xiàn)程。 至此await執(zhí)行結(jié)束

singnal的原理
public final void signal() {
    if (!isHeldExclusively()) //只有當(dāng)前線(xiàn)程持有了鎖,才能釋放
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);//優(yōu)先釋放隊(duì)列頭的,也就是等待時(shí)間最長(zhǎng)的condition node
}
private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}
//將節(jié)點(diǎn)從condition queue轉(zhuǎn)移到sync queue
final boolean transferForSignal(Node node) {
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false; //設(shè)置為非等待失敗,則不繼續(xù)轉(zhuǎn)移
//CAS設(shè)置等待狀態(tài)為0成功
Node p = enq(node); //新節(jié)點(diǎn)放入sync queue,并返回原來(lái)的尾部節(jié)點(diǎn),也就是新節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)
    int ws = p.waitStatus;
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) //參考shouldParkAfterFailedAcquire
        LockSupport.unpark(node.thread);//如果當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)線(xiàn)程已經(jīng)取消,或者將當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)線(xiàn)程的waitStatus設(shè)置成SIGNAL失敗,則直接喚醒當(dāng)前線(xiàn)程
    return true;
}

可以看到signal最關(guān)鍵的信息就是去掉等待隊(duì)列中的CONDITION狀態(tài),并將線(xiàn)程加入sync隊(duì)列,至此signal結(jié)束

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/72416.html

相關(guān)文章

  • 高并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線(xiàn)程安全并且高效的,在并發(fā)編程中經(jīng)常可見(jiàn)它的使用,在開(kāi)始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話(huà),看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽(tīng)名字多牛逼,來(lái),我們一步一步來(lái)?yè)羝魄皟蓚€(gè)名詞,今天我們首先來(lái)說(shuō)說(shuō)分布式。 探究...

    supernavy 評(píng)論0 收藏0
  • 高并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線(xiàn)程安全并且高效的,在并發(fā)編程中經(jīng)常可見(jiàn)它的使用,在開(kāi)始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話(huà),看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽(tīng)名字多牛逼,來(lái),我們一步一步來(lái)?yè)羝魄皟蓚€(gè)名詞,今天我們首先來(lái)說(shuō)說(shuō)分布式。 探究...

    ddongjian0000 評(píng)論0 收藏0
  • 高并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線(xiàn)程安全并且高效的,在并發(fā)編程中經(jīng)常可見(jiàn)它的使用,在開(kāi)始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話(huà),看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽(tīng)名字多牛逼,來(lái),我們一步一步來(lái)?yè)羝魄皟蓚€(gè)名詞,今天我們首先來(lái)說(shuō)說(shuō)分布式。 探究...

    wangdai 評(píng)論0 收藏0
  • Java多線(xiàn)程進(jìn)階(七)—— J.U.C之locks框架:AQS獨(dú)占功能剖析(2)

    摘要:開(kāi)始獲取鎖終于輪到出場(chǎng)了,的調(diào)用過(guò)程和完全一樣,同樣拿不到鎖,然后加入到等待隊(duì)列隊(duì)尾然后,在阻塞前需要把前驅(qū)結(jié)點(diǎn)的狀態(tài)置為,以確保將來(lái)可以被喚醒至此,的執(zhí)行也暫告一段落了安心得在等待隊(duì)列中睡覺(jué)。 showImg(https://segmentfault.com/img/remote/1460000016012467); 本文首發(fā)于一世流云的專(zhuān)欄:https://segmentfault...

    JayChen 評(píng)論0 收藏0
  • JAVA并發(fā)編程之-ReentrantLock鎖原理解讀

    摘要:作者畢來(lái)生微信鎖狀態(tài)轉(zhuǎn)換分類(lèi)以后幫助我們提供了線(xiàn)程同步機(jī)制,通過(guò)顯示定義同步鎖來(lái)實(shí)現(xiàn)對(duì)象之間的同步。等待重新嘗試因?yàn)樵谥惺怯藐P(guān)鍵字聲明的,故可以在線(xiàn)程間可見(jiàn)再次判斷一下能否持有鎖可能線(xiàn)程同步代碼執(zhí)行得比較快,已經(jīng)釋放了鎖,不可以就返回。 作者 : 畢來(lái)生微信: 878799579 鎖狀態(tài)轉(zhuǎn)換 showImg(https://segmentfault.com/img/remote/...

    荊兆峰 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<