成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【java并發(fā)編程實(shí)戰(zhàn)6】AQS之獨(dú)占鎖ReentrantLock實(shí)現(xiàn)

sixleaves / 2587人閱讀

摘要:鎖與很好的隔離使用者與實(shí)現(xiàn)者所需要關(guān)注的領(lǐng)域。那么這個(gè)就是包裝線(xiàn)程并且放入到隊(duì)列的過(guò)程實(shí)現(xiàn)的方法。也證實(shí)了就是獲取鎖的線(xiàn)程的節(jié)點(diǎn)。如果發(fā)生異常取消請(qǐng)求,也就是將當(dāng)前節(jié)點(diǎn)重隊(duì)列中移除。

前言

自從JDK1.5后,jdk新增一個(gè)并發(fā)工具包java.util.concurrent,提供了一系列的并發(fā)工具類(lèi)。而今天我們需要學(xué)習(xí)的是java.util.concurrent.lock也就是它下面的lock包,其中有一個(gè)最為常見(jiàn)類(lèi)ReentrantLock,

我們知道ReentrantLock的功能是實(shí)現(xiàn)代碼段的并發(fā)訪(fǎng)問(wèn)控制,也就是通常意義上所說(shuō)的鎖。之前我們也學(xué)習(xí)過(guò)一種鎖的實(shí)現(xiàn),也就是synchronized關(guān)鍵詞,synchronized是在字節(jié)碼層面,通過(guò)對(duì)象的監(jiān)視器鎖實(shí)現(xiàn)的。那么ReentrantLock又是怎么實(shí)現(xiàn)的呢?

如果不看源碼,可能會(huì)以為它的實(shí)現(xiàn)是通過(guò)類(lèi)似于synchronized,通過(guò)對(duì)象的監(jiān)視器鎖實(shí)現(xiàn)的。但事實(shí)上它僅僅是一個(gè)工具類(lèi)!沒(méi)有使用更“高級(jí)”的機(jī)器指令,不是關(guān)鍵字,也不依靠JDK編譯時(shí)的特殊處理,僅僅作為一個(gè)普普通通的類(lèi)就完成了代碼塊的并發(fā)訪(fǎng)問(wèn)控制,這就更讓人疑問(wèn)它怎么實(shí)現(xiàn)的代碼塊的并發(fā)訪(fǎng)問(wèn)控制的了。

我們查看源碼發(fā)現(xiàn),它是通過(guò)繼承抽象類(lèi)實(shí)現(xiàn)的AbstractQueuedSynchronizer,為了方便描述,接下來(lái)我將用AQS代替AbstractQueuedSynchronizer。

關(guān)于AQS
AQS,它是用來(lái)構(gòu)建鎖或者其他同步組建的基礎(chǔ)框架,我們見(jiàn)過(guò)許多同步工具類(lèi)都是基于它構(gòu)建的。包括ReentrantLock、CountDownLatch等。在深入了解AQS了解之前,我們需要知道鎖跟AQS的區(qū)別。鎖,它是面向使用者的,它定義了使用者與鎖交互的接口,隱藏了實(shí)現(xiàn)的細(xì)節(jié);而AQS面像的是鎖的實(shí)現(xiàn)者,它簡(jiǎn)化了鎖的實(shí)現(xiàn)。鎖與AQS很好的隔離使用者與實(shí)現(xiàn)者所需要關(guān)注的領(lǐng)域。那么我們今天就作為一個(gè)鎖的實(shí)現(xiàn)者,一步一步分析鎖的實(shí)現(xiàn)。

AQS又稱(chēng)同步器,它的內(nèi)部有一個(gè)int成員變量state表示同步狀態(tài),還有一個(gè)內(nèi)置的FIFO隊(duì)列來(lái)實(shí)現(xiàn)資源獲取線(xiàn)程的排隊(duì)工作。通過(guò)它們我們就能實(shí)現(xiàn)鎖。

在實(shí)現(xiàn)鎖之前,我們需要考慮做為鎖的使用者,鎖會(huì)有哪幾種?

通常來(lái)說(shuō),鎖分為兩種,一種是獨(dú)占鎖(排它鎖,互斥鎖),另一種就是共享鎖了。根據(jù)這兩類(lèi),其實(shí)AQS也給我們提供了兩套API。而我們作為鎖的實(shí)現(xiàn)者,通常都是要么全部實(shí)現(xiàn)它的獨(dú)占api,要么實(shí)現(xiàn)它的共享api,而不會(huì)出現(xiàn)一起實(shí)現(xiàn)的。即使juc內(nèi)置的ReentrantReadWriteLock也是通過(guò)兩個(gè)子類(lèi)分別來(lái)實(shí)現(xiàn)的。

鎖的實(shí)現(xiàn) 獨(dú)占鎖

獨(dú)占鎖又名互斥鎖,同一時(shí)間,只有一個(gè)線(xiàn)程能獲取到鎖,其余的線(xiàn)程都會(huì)被阻塞等待。其中我們常用的ReentrantLock就是一種獨(dú)占鎖,我們一起來(lái)ReentrantLock 分析ReentrantLock的同時(shí)看一看AQS的實(shí)現(xiàn),再推理出AQS獨(dú)特的設(shè)計(jì)思路和實(shí)現(xiàn)方式。最后,再看其共享控制功能的實(shí)現(xiàn)。

首先我們來(lái)看看獲取鎖的過(guò)程

加鎖

我們查看ReentrantLock的源碼。來(lái)分析它的lock方法

  public void lock() {
        sync.lock();
   }

與我們之前分析的一樣,鎖的具體實(shí)現(xiàn)由內(nèi)部的代理類(lèi)完成,lock只是暴露給鎖的使用者的一套api。使用過(guò)ReentrantLock的同學(xué)應(yīng)該知道,ReentrantLock又分為公平鎖和非公平鎖,所以,ReentrantLock內(nèi)部只有兩個(gè)sync的實(shí)現(xiàn)。

    /**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync{..}
     /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync{..}

公平鎖 :每個(gè)線(xiàn)程獲取鎖的順序是按照調(diào)用lock方法的先后順序來(lái)的。

非公平鎖:每個(gè)線(xiàn)程獲取鎖的順序是不會(huì)按照調(diào)用lock方法的先后順序來(lái)的。完全看運(yùn)氣。

所以我們完全可以猜測(cè)到,這個(gè)公平與不公平的區(qū)別就體現(xiàn)在鎖的獲取過(guò)程。我們以公平鎖為例,來(lái)分析獲取鎖過(guò)程,最后對(duì)比非公平鎖的過(guò)程,尋找差異。

lock

查看FairSync的lock方法

    final void lock() {
            acquire(1);
        }

這里它調(diào)用到了父類(lèi)AQS的acquire方法,所以我們繼續(xù)查看acquire方法的代碼

acquire
/**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
        if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 
            selfInterrupt();
    }

查看方法方法的注釋我們可以知道這個(gè)方法的作用,這里我簡(jiǎn)單的翻譯一下.

Acquires方法是一個(gè)獨(dú)占鎖模式的方法,它是不會(huì)響應(yīng)中斷的。它至少執(zhí)行一次tryAcquire去獲取鎖,如果返回true,則代表獲取鎖成功,否則它將會(huì)被加入等待隊(duì)列阻塞,直到重新嘗試獲取鎖成功。所以我們需要看看嘗試獲取鎖的方法tryAcquire的實(shí)現(xiàn)

tryAcruire
   protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

拋出一個(gè)異常,沒(méi)有實(shí)現(xiàn)。所以我們需要查看它的子類(lèi),在我們這里就是FairSync的實(shí)現(xiàn)。

這里也會(huì)大家會(huì)有疑惑,沒(méi)有實(shí)現(xiàn)為什么不寫(xiě)成抽象方法呢,前面我們提到過(guò),我們不會(huì)同時(shí)在一個(gè)類(lèi)中實(shí)現(xiàn)獨(dú)占鎖跟共享鎖的api,那么tryAcruire是屬于獨(dú)占鎖,那么如果我想一個(gè)共享鎖也要重新獨(dú)占鎖的方法嗎?所以大師的設(shè)計(jì)是絕對(duì)沒(méi)有問(wèn)題的。
protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();//獲取當(dāng)前線(xiàn)程
            int c = getState();  //獲取父類(lèi)AQS中的標(biāo)志位
            if (c == 0) {
                if (!hasQueuedPredecessors() && 
                    //如果隊(duì)列中沒(méi)有其他線(xiàn)程  說(shuō)明沒(méi)有線(xiàn)程正在占有鎖!
                    compareAndSetState(0, acquires)) { 
                    //修改一下?tīng)顟B(tài)位,注意:這里的acquires是在lock的時(shí)候傳遞來(lái)的,從上面的圖中可以知道,這個(gè)值是寫(xiě)死的1
                    setExclusiveOwnerThread(current);
                    //如果通過(guò)CAS操作將狀態(tài)為更新成功則代表當(dāng)前線(xiàn)程獲取鎖,因此,將當(dāng)前線(xiàn)程設(shè)置到AQS的一個(gè)變量中,說(shuō)明這個(gè)線(xiàn)程拿走了鎖。
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
             //如果不為0 意味著,鎖已經(jīng)被拿走了,但是,因?yàn)镽eentrantLock是重入鎖,
             //是可以重復(fù)lock,unlock的,只要成對(duì)出現(xiàn)行。一次。這里還要再判斷一次 獲取鎖的線(xiàn)程是不是當(dāng)前請(qǐng)求鎖的線(xiàn)程。
                int nextc = c + acquires;//如果是的,累加在state字段上就可以了。
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

目前為止,如果獲取鎖成功,則返回true,獲取鎖的過(guò)程結(jié)束,如果獲取失敗,則返回false

按照之前的邏輯,如果線(xiàn)程獲取鎖失敗,則會(huì)被放入到隊(duì)列中,但是在放入之前,需要給線(xiàn)程包裝一下。

那么這個(gè)addWaiter就是包裝線(xiàn)程并且放入到隊(duì)列的過(guò)程實(shí)現(xiàn)的方法。

addWaiter
   /**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // 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)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

注釋: 把當(dāng)前線(xiàn)程作為一個(gè)節(jié)點(diǎn)添加到隊(duì)列中,并且為這個(gè)節(jié)點(diǎn)設(shè)置模式

模式: 也就是獨(dú)占模式/共享模式,在這里模式是形參,所以我們看看起調(diào)方

acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) Node.EXCLUSIVE 就代表這是獨(dú)占鎖模式。

創(chuàng)建好節(jié)點(diǎn)后,將節(jié)點(diǎn)加入到隊(duì)列尾部,此處,在隊(duì)列不為空的時(shí)候,先嘗試通過(guò)cas方式修改尾節(jié)點(diǎn)為最新的節(jié)點(diǎn),如果修改失敗,意味著有并發(fā),這個(gè)時(shí)候才會(huì)進(jìn)入enq中死循環(huán),“自旋”方式修改。

將線(xiàn)程的節(jié)點(diǎn)接入到隊(duì)里中后,當(dāng)然還需要做一件事:將當(dāng)前線(xiàn)程掛起!這個(gè)事,由acquireQueued來(lái)做。

在解釋acquireQueued之前,我們需要先看下AQS中隊(duì)列的內(nèi)存結(jié)構(gòu),我們知道,隊(duì)列由Node類(lèi)型的節(jié)點(diǎn)組成,其中至少有兩個(gè)變量,一個(gè)封裝線(xiàn)程,一個(gè)封裝節(jié)點(diǎn)類(lèi)型。

而實(shí)際上,它的內(nèi)存結(jié)構(gòu)是這樣的(第一次節(jié)點(diǎn)插入時(shí),第一個(gè)節(jié)點(diǎn)是一個(gè)空節(jié)點(diǎn),代表有一個(gè)線(xiàn)程已經(jīng)獲取鎖,事實(shí)上,隊(duì)列的第一個(gè)節(jié)點(diǎn)就是代表持有鎖的節(jié)點(diǎn)):

黃色節(jié)點(diǎn)為隊(duì)列默認(rèn)的頭節(jié)點(diǎn),每次有線(xiàn)程競(jìng)爭(zhēng)失敗,進(jìn)入隊(duì)列后其實(shí)都是插入到隊(duì)列的尾節(jié)點(diǎn)(tail后面)后面。這個(gè)從enq方法可以看出來(lái),上文中有提到enq方法為將節(jié)點(diǎn)插入隊(duì)列的方法:

enq
private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                // 一個(gè)空的節(jié)點(diǎn),通常代表獲取鎖的線(xiàn)程
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }
acquireQueued

接著我們來(lái)看看當(dāng)節(jié)點(diǎn)被放入到隊(duì)列中,如何將線(xiàn)程掛起,也就是看看acquireQueued方法的實(shí)現(xiàn)。

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 獲取當(dāng)前節(jié)點(diǎn)前驅(qū)結(jié)點(diǎn)
                final Node p = node.predecessor();
                // 如果前驅(qū)節(jié)點(diǎn)是head,那么它就是等待隊(duì)列中的第一個(gè)線(xiàn)程
                // 因?yàn)槲覀冎纇ead就是獲取線(xiàn)程的節(jié)點(diǎn),那么它就有機(jī)會(huì)再次獲取鎖
                if (p == head && tryAcquire(arg)) {
                    //成功后,將上圖中的黃色節(jié)點(diǎn)移除,Node1變成頭節(jié)點(diǎn)。 也證實(shí)了head就是獲取鎖的線(xiàn)程的節(jié)點(diǎn)。
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // 1、檢查前一個(gè)節(jié)點(diǎn)的狀態(tài),判斷是否要掛起
                // 2、如果需要掛起,則通過(guò)JUC下的LockSopport類(lèi)的靜態(tài)方法park掛起當(dāng)前線(xiàn)程,直到被喚醒。
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            // 如果發(fā)生異常
            if (failed)
                // 取消請(qǐng)求,也就是將當(dāng)前節(jié)點(diǎn)重隊(duì)列中移除。
                cancelAcquire(node);
        }
    }

這里我還需要解釋的是:

1、Node節(jié)點(diǎn)除了存儲(chǔ)當(dāng)前線(xiàn)程之外,節(jié)點(diǎn)類(lèi)型,前驅(qū)后驅(qū)指針之后,還存儲(chǔ)一個(gè)叫waitStatus的變量,該變量用于描述節(jié)點(diǎn)的狀態(tài)。共有四種狀態(tài)。

       /** waitStatus value to indicate thread has cancelled */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor"s thread needs unparking */
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
        static final int PROPAGATE = -3;

分別表示:

1 = 取消狀態(tài),該節(jié)點(diǎn)將會(huì)被隊(duì)列移除。

-1 = 等待狀態(tài),后驅(qū)節(jié)點(diǎn)處于等待狀態(tài)。

-2 = 等待被通知,該節(jié)點(diǎn)將會(huì)阻塞至被該鎖的condition的await方法喚醒。

-3 = 共享傳播狀態(tài),代表該節(jié)點(diǎn)的狀態(tài)會(huì)向后傳播。

到此為止,一個(gè)線(xiàn)程對(duì)于鎖的一次競(jìng)爭(zhēng)才告于段落,結(jié)果有兩種,要么成功獲取到鎖(不用進(jìn)入到AQS隊(duì)列中),要么,獲取失敗,被掛起,等待下次喚醒后繼續(xù)循環(huán)嘗試獲取鎖,值得注意的是,AQS的隊(duì)列為FIFO隊(duì)列,所以,每次被CPU假喚醒,且當(dāng)前線(xiàn)程不是出在頭節(jié)點(diǎn)的位置,也是會(huì)被掛起的。AQS通過(guò)這樣的方式,實(shí)現(xiàn)了競(jìng)爭(zhēng)的排隊(duì)策略。

釋放鎖

看完了加鎖,再看釋放鎖。我們先不看代碼也可以猜測(cè)到釋放鎖需要的步驟。

隊(duì)列的頭節(jié)點(diǎn)是當(dāng)前獲取鎖的線(xiàn)程,所以我們需要移除頭節(jié)點(diǎn)

釋放鎖,喚醒頭節(jié)點(diǎn)后驅(qū)節(jié)點(diǎn)來(lái)競(jìng)爭(zhēng)鎖

接下來(lái)我們查看源碼來(lái)驗(yàn)證我們的猜想是否在正確。

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

unlock方法調(diào)用AQS的release方法,因?yàn)槲覀兊腶cquire的時(shí)候傳入的是1,也就是同步狀態(tài)量+1,那么對(duì)應(yīng)的解鎖就要-1。

release
  public final boolean release(int arg) {
        // 嘗試釋放鎖
        if (tryRelease(arg)) {
            // 釋放鎖成功,獲取當(dāng)前隊(duì)列的頭節(jié)點(diǎn)
            Node h = head;
            if (h != null && h.waitStatus != 0)
                // 喚醒當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
tryRelease

同樣的它是交給子類(lèi)實(shí)現(xiàn)的

    protected final boolean tryRelease(int releases) {
        
            int c = getState() - releases;
            // 當(dāng)前線(xiàn)程不是獲取鎖的線(xiàn)程 拋出異常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            // 因?yàn)槭侵厝氲年P(guān)系,不是每次釋放鎖c都等于0,直到最后一次釋放鎖時(shí),才通知AQS不需要再記錄哪個(gè)線(xiàn)程正在獲取鎖。
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
    }
unparkSuccessor

釋放鎖成功之后,就喚醒頭節(jié)點(diǎn)后驅(qū)節(jié)點(diǎn)來(lái)競(jìng)爭(zhēng)鎖

 private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        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;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

值得注意的是,尋找的順序是從隊(duì)列尾部開(kāi)始往前去找的最前面的一個(gè)waitStatus小于0的節(jié)點(diǎn)。因?yàn)榇笥? 就是1狀態(tài)的節(jié)點(diǎn)是取消狀態(tài)。

公平鎖與非公平鎖

到此我們鎖獲取跟鎖的釋放已經(jīng)分析的差不多。那么公平鎖跟非公平鎖的區(qū)別在于加鎖的過(guò)程。對(duì)比代碼

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

        final void lock() {
            acquire(1);
        }
}
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);
        }
}

從代碼中也可以看出來(lái),非公平在公平鎖的加鎖的邏輯之前先直接cas修改一次state變量(嘗試獲取鎖),成功就返回,不成功再排隊(duì),從而達(dá)到不排隊(duì)直接搶占的目的。

最后歡迎大家關(guān)注一下我的個(gè)人公眾號(hào)。一起交流一起學(xué)習(xí),有問(wèn)必答。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77100.html

相關(guān)文章

  • BATJ都愛(ài)問(wèn)的多線(xiàn)程面試題

    摘要:今天給大家總結(jié)一下,面試中出鏡率很高的幾個(gè)多線(xiàn)程面試題,希望對(duì)大家學(xué)習(xí)和面試都能有所幫助。指令重排在單線(xiàn)程環(huán)境下不會(huì)出先問(wèn)題,但是在多線(xiàn)程環(huán)境下會(huì)導(dǎo)致一個(gè)線(xiàn)程獲得還沒(méi)有初始化的實(shí)例。使用可以禁止的指令重排,保證在多線(xiàn)程環(huán)境下也能正常運(yùn)行。 下面最近發(fā)的一些并發(fā)編程的文章匯總,通過(guò)閱讀這些文章大家再看大廠面試中的并發(fā)編程問(wèn)題就沒(méi)有那么頭疼了。今天給大家總結(jié)一下,面試中出鏡率很高的幾個(gè)多線(xiàn)...

    高勝山 評(píng)論0 收藏0
  • Java 重入 ReentrantLock 原理分析

    摘要:的主要功能和關(guān)鍵字一致,均是用于多線(xiàn)程的同步。而僅支持通過(guò)查詢(xún)當(dāng)前線(xiàn)程是否持有鎖。由于和使用的是同一把可重入鎖,所以線(xiàn)程可以進(jìn)入方法,并再次獲得鎖,而不會(huì)被阻塞住。公平與非公平公平與非公平指的是線(xiàn)程獲取鎖的方式。 1.簡(jiǎn)介 可重入鎖ReentrantLock自 JDK 1.5 被引入,功能上與synchronized關(guān)鍵字類(lèi)似。所謂的可重入是指,線(xiàn)程可對(duì)同一把鎖進(jìn)行重復(fù)加鎖,而不會(huì)被阻...

    lx1036 評(píng)論0 收藏0
  • Java多線(xiàn)程進(jìn)階(七)—— J.U.Clocks框架: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ù)雜嗎?

    摘要:撤銷(xiāo)鎖偏向鎖使用了一種等到競(jìng)爭(zhēng)出現(xiàn)才釋放鎖的機(jī)制,所以當(dāng)其他線(xiàn)程嘗試競(jìng)爭(zhēng)偏向鎖時(shí),持有偏向鎖的線(xiàn)程才會(huì)釋放鎖。輕量級(jí)鎖線(xiàn)程在執(zhí)行同步代碼塊之前,會(huì)先在當(dāng)前線(xiàn)程的棧楨中創(chuàng)建用于存儲(chǔ)鎖記錄的空間,并將對(duì)象頭中的復(fù)制到鎖記錄中,官方稱(chēng)為。 前言 作者前面也寫(xiě)了幾篇關(guān)于Java并發(fā)編程,以及線(xiàn)程和volatil的基礎(chǔ)知識(shí),有興趣可以閱讀作者的原文博客,今天關(guān)于Java中的兩種鎖進(jìn)行詳解,希望對(duì)...

    Darkgel 評(píng)論0 收藏0

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

0條評(píng)論

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