真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JDK里的自旋鎖怎么用

這篇文章主要為大家展示了“JDK里的自旋鎖怎么用”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“JDK里的自旋鎖怎么用”這篇文章吧。

我們提供的服務有:網(wǎng)站建設、做網(wǎng)站、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、中陽ssl等。為數(shù)千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的中陽網(wǎng)站制作公司

自旋鎖是采用讓當前線程不停地的在循環(huán)體內執(zhí)行實現(xiàn)的,當循環(huán)的條件被其他線程改變時才能進入臨界區(qū)。

JDK里面自旋鎖的實現(xiàn)有 SynchronousQueue  和 LinkedTransferQueue。  

先說公平鎖,先等待的線程先獲得數(shù)據(jù)。SynchronousQueue的內部類TransferQueue實現(xiàn)了公平鎖。

某一時刻 線程A看到內存的情況如下:   鏈表,head 和 tail 分別指向鏈首和鏈尾,并且線程執(zhí)行了ht = tail 。

*
*  head            ht=tail
*    |               |
*    v               v*    M ->  U -> U -> U*

M 代表match , 表示該節(jié)點已經(jīng)匹配到了數(shù)據(jù),  poll 等到了 offer ,或者 offer 等到了 poll 。

U 代表unmatch , 表示該節(jié)點在等待填充數(shù)據(jù)或者數(shù)據(jù)等待poll 。

由于并發(fā)操作,經(jīng)過其他線程的操作使得鏈表變成如下:(此操作是瞬間完成的)

*   head            ht      tail
*    |              |         |
*    v              v         v
*    M -> M -> U -> U -> U -> U*

有兩個U節(jié)點添加進來, 第二個節(jié)點M匹配到了數(shù)據(jù)。

假設此時線程A想再往鏈表添加U節(jié)點:

那么需要進行那些操作?

1: 發(fā)現(xiàn)ht != tail , 于是需要繼續(xù)循環(huán)

2:在 ht == tail 的情況下需要先 判斷 tail.next 是否為null , 如果不是則繼續(xù)循環(huán)

3:新建一個node,將 tail.next 指向新node。

4:將U賦值給tail 。    (如果只執(zhí)行了3而還沒有執(zhí)行4,就會出現(xiàn)2中的情況,ht=tail,但是ht.next 為空,說明此時有線程執(zhí)行了3操作但是還沒有執(zhí)行4操作,此時只需要繼續(xù)循環(huán)即可)

*  head           ht=tail*    |              |*    v              v*    U -> U -> U -> U -> U
/* *   head                tail *    |                   | *    v                   v
 *    U -> U -> U -> U -> U
 * */

5:  自旋等待match。

6: 等待結束有兩種可能結果: 6.1 超時取消    6.2 成功  

成功時: 因此只需將 head 指向node.next . 并且將 node.next 置空。 雖然此時   M -> M  但是只要其它線程正確的執(zhí)行了M.next = null 即可。

/* *                  head                    tail *                   |                        | *                   v                        v
 *    M  M  M  M  M  M -> M -> U -> U - > U ->U
 * *//*
 *                           head          tail
 *                            |              |
 *                            v              v
 *    M  M  M  M  M  M ->  M  U -> U - > U ->U
 *
 */

等待超時:此時U按理也應該來到了鏈首,前面node的也都超時了,但萬一其他的線程沒有獲得cpu呢,就會出現(xiàn)如下的狀況,需要將U前面的幾個node也順便清理掉

/* *                  head                    tail *                   |                        | *                   v                        v *    M  M  M  M  M  U -> U -> U -> U - > U ->U * */

假設此時線程A是想將U變成M,這個邏輯很簡單,按順序找到一個U,嘗試給U的item賦值。成功結束,不成功繼續(xù)循環(huán)。

E transfer(E e, boolean timed, long nanos) {    QNode s = null; // constructed/reused as needed    boolean isData = (e != null);    for (;;) {
        QNode t = tail;        QNode h = head;        if (t == null || h == null)         // saw uninitialized value            continue;                       // spin        if (h == t || t.isData == isData) { // empty or same-mode            QNode tn = t.next;            if (t != tail)                  // inconsistent read                continue;            if (tn != null) {               // lagging tail                advanceTail(t, tn);                continue;            }if (timed && nanos <= 0)        // can't wait                return null;            if (s == null)
                s = new QNode(e, isData);            if (!t.casNext(null, s))        // failed to link in                continue;            advanceTail(t, s);              // swing tail and wait            Object x = awaitFulfill(s, e, timed, nanos);            if (x == s) {                   // wait was cancelled                clean(t, s);                return null;            }if (!s.isOffList()) {           // not already unlinked                advanceHead(t, s);          // unlink if head                if (x != null)              // and forget fields                    s.item = s;                s.waiter = null;            }return (x != null) ? (E)x : e;        } else {                            // complementary-mode            QNode m = h.next;               // node to fulfill            if (t != tail || m == null || h != head)continue;                   // inconsistent read            Object x = m.item;            if (isData == (x != null) ||    // m already fulfilled                x == m ||                   // m cancelled                !m.casItem(x, e)) {         // lost CAS                advanceHead(h, m);          // dequeue and retry                continue;            }

            advanceHead(h, m);              // successfully fulfilled            LockSupport.unpark(m.waiter);            return (x != null) ? (E)x : e;        }
    }
}

自旋分析:

Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {/* Same idea as TransferStack.awaitFulfill */    final long deadline = timed ? System.nanoTime() + nanos : 0L;    Thread w = Thread.currentThread();    int spins = ((head.next == s) ?
                 (timed ? maxTimedSpins : maxUntimedSpins) : 0);    for (;;) {if (w.isInterrupted())
            s.tryCancel(e);        Object x = s.item;        if (x != e)return x;        if (timed) {
            nanos = deadline - System.nanoTime();            if (nanos <= 0L) {
                s.tryCancel(e);                continue;            }
        }if (spins > 0)
            --spins;        else if (s.waiter == null)
            s.waiter = w;        else if (!timed)
            LockSupport.park(this);        else if (nanos > spinForTimeoutThreshold)
            LockSupport.parkNanos(this, nanos);    }
}

循環(huán)判斷 node.item 有沒有變化,如果有變化則匹配成功,如果沒有則繼續(xù)循環(huán), 循環(huán)一定的次數(shù)(spins)后還沒有匹配成功則使用 LockSupport.park() 來阻塞線程。這個循環(huán)過程即可稱為自旋。

但是公平鎖存在一個問題:

/* * *  head            ht=tail *    |               | *    v               v *    M ->  U -> U -> U *   
 *   | *   | *  U變成M,但是此線程并沒有獲得cpu,沒法立即執(zhí)行,于是后面獲得cpu的線程便有了意見,為啥不將數(shù)據(jù)給我,我能立即執(zhí)行。 */

要想解決此問題說來也十分簡單,每個線程只需不停的將自己的node和head進行交換(casHead)即可優(yōu)先獲得task。 這個是在 TransferStack中實現(xiàn)的,說起來簡單,但實現(xiàn)起來則困難得多。其實這也是經(jīng)常聽到的搶占式執(zhí)行吧,SynchronousQueue 默認使用非公平鎖。

public SynchronousQueue() {this(false);}public SynchronousQueue(boolean fair) {transferer = fair ? new TransferQueue() : new TransferStack();}

以上是“JDK里的自旋鎖怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


當前題目:JDK里的自旋鎖怎么用
鏈接地址:http://weahome.cn/article/jocogp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部