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

資訊專欄INFORMATION COLUMN

AbstractQueuedSynchronizer源代碼分析(未完成)

zhunjiee / 1652人閱讀

摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會被掛起或者是自旋,然后當線程釋放鎖后,線程再被喚醒,以此類推,按照申請鎖的先后順序來。

Node exclusive lock(獨占鎖) ReentrantLock

ReentrantLock實現了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。
公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會被掛起或者是自旋,然后當線程A釋放鎖后,線程B再被喚醒,以此類推,按照申請鎖的先后順序來。
非公平鎖: 線程A占用鎖,B等待,于此同時C請求鎖,由于B線程被喚醒需要時間,所以C有可能在B被喚醒錢就釋放鎖,以此類推,按照鎖空閑時申請鎖的線程為優先。

世界應該是公平公正的不是嗎?好了,別白日做夢了,由于線程的喚醒是一個比較耗時的操作(切換線程上下文,調用OS等)如果線程持有鎖的時間很長,那么公平鎖就比較有優勢

NonfairSync

NonfairSync中lock的實現如下:

final void lock() {
    // CAS操作設置AbstractQueuedSynchronizer中的volatile int state
    // 如果設置成功將現有的線程setExclusiveOwnerThread
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
    // CAS失敗了就調用acquire()方法
        acquire(1);
}

acquire方法由AbstractQueuedSynchronizer提供

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    selfInterrupt();
}

tryAcquire在AbstractQueuedSynchronizer中是一個protected方法并且沒有給出實現,可見是希望由它的子類去擴展

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

回去再看NonfairSync中tryAcquire的實現

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    // 獲取同步state
    int c = getState();
    // 這個判斷很有意思,由于調用這個方式是第一次嘗試CAS失敗才會進入該方法
    // 這里重新再判斷一次同步state,可以避免之前的線程已經釋放lock,而繼續將
    // 該線程放入等待隊列的情況,和lock()的第一段代碼含義相同設置同步state
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 接下來判斷是否是同一個線程,這個判斷是因為ReentrantLock是可重入的lock
    else if (current == getExclusiveOwnerThread()) {
        // 將state++,這里的lock的獲取就是通過同步state的值來控制的
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

這段代碼大概的意思就是如果還沒有線程占用鎖就設置state為1,如果是已經占用該鎖的線程再次訪問就累計state的值,返回true,如果已經被占用返回false

回過頭來繼續看acquire,!tryAcquire(arg)意味著獲取鎖失敗,然后執行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
進入addWaiter方法

/**
 * 1. 初始化: 如果tail和head沒有被初始化,那么創建一個node并且指向它
 * +------+
 * | Node | <---- tail, head
 * |(Head)|
 * +------+
 * 
 * 2. 添加新的節點進入隊列
 *            +------+  prev +------+
 * head ----> | Node | <---- | Node | <---- tail
 *            |(Head)| ----> |Thread|
 *            +------+  next +------+
 */
private Node addWaiter(Node mode) {
    // 創建一個node使用EXCLUSIVE模式
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    // 如果隊列不是null(已經有線程再等待鎖)那么將該新增的node加入隊列
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    // 如果上述代碼沒有成功,這里是使用自旋的方式繼續加入等待隊列
    enq(node);
    // 入隊成功后返回新增node節點
    return node;
}

// 將新的node節點入隊并返回之前的tail節點
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 典型的入隊操作將tail指向新增的node
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

然后再看acquireQueued,此時的node參數是之前我們分析的新增入隊列的node節點

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            // 返回node的前一個節點
            final Node p = node.predecessor();
            /**
             * 如果該新增node的prev-node是head-node.如下圖這種狀態
             * 也就是說在等待隊列中只有一個node,Head-node不包含在
             * 內,并且調用tryAcquire方法成功(即成功的設置了同步state)
             * 
             * 
             *            +------+  prev +------+
             * head ----> | Node | <---- | Node | <---- tail
             *            |(Head)| ----> |Thread|
             *            +------+  next +------+
             *
             * 那么將head指向改node,原來的head的next節點為null
             * 
             *             +-------------+
             * head ---->  | Node        | <---- tail
             *             |Thread = null|
             *             +-------------+
             *
             */
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            // 
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
     } finally {
         if (failed)
            cancelAcquire(node);
     }
}

接下來是shouldParkAfterFailedAcquire,顧名思義該方法返回是否在獲取lock失敗后堵塞線程,該方法會忽略并移出隊列中node.waitStatus = CANCELLED的node

/** 
 * 該方的參數是 pred是Thread-A所在的node,node是Thread-B所在的node
 * 這個必須得理解
 * 
 *            +------+  prev +--------------+  prev +--------+
 * head ----> | Node | <---- | Node         | <---- | Node   |<---- tail
 *            |(Head)| ----> |Thread-A      | ----> |Thread-B|
 *            +------+  next |waitStatus = 0|       |        |
 *                           +--------------+       +--------+
 * 
 *            +------+  prev +---------------+  prev +--------+
 * head ----> | Node | <---- | Node          | <---- | Node   |<---- tail
 *            |(Head)| ----> |Thread-A       | ----> |Thread-B|
 *            +------+  next |waitStatus = -1|       |        |
 *                           +---------------+       +--------+
 *
 * static final int CANCELLED =  1;
 * static final int SIGNAL    = -1;
 * static final int CONDITION = -2;
 * static final int PROPAGATE = -3;
 *
 * 同時這個方法又分為2步(似乎整個AQS中都充斥著延遲初始化的概念)
 * 1. 初始化: 設置形參pred的waitStatus屬性為Node.SIGNAL
 * 2. 由于調用shouldParkAfterFailedAcquire()方法的acquireQueued()方法
 * 還在自旋中,所以該方法會被調用第2次,這次才真正返回true,如果waitStatus
 * 被設置成CANCELLED,那么會忽略等待隊列中的這些node
 * 
 */
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don"t park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
        // 這里就是初始化的代碼,設置形參pred的waitStatus屬性為Node.SIGNAL
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

parkAndCheckInterrupt()方法,使用LockSupport堵塞當前node對應的thread,并返回中斷標識,當這個方法被調用時才真正的意味著lock.lock()方法完成了它的使命

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}
補充說明 unsafe類

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76293.html

相關文章

  • AbstractQueuedSynchronizer代碼分析(完成)

    摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會被掛起或者是自旋,然后當線程釋放鎖后,線程再被喚醒,以此類推,按照申請鎖的先后順序來。 Node exclusive lock(獨占鎖) ReentrantLock ReentrantLock實現了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會被掛起或...

    omgdog 評論0 收藏0
  • AbstractQueuedSynchronizer代碼分析(完成)

    摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會被掛起或者是自旋,然后當線程釋放鎖后,線程再被喚醒,以此類推,按照申請鎖的先后順序來。 Node exclusive lock(獨占鎖) ReentrantLock ReentrantLock實現了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會被掛起或...

    chanjarster 評論0 收藏0
  • AbstractQueuedSynchronizer代碼分析(完成)

    摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會被掛起或者是自旋,然后當線程釋放鎖后,線程再被喚醒,以此類推,按照申請鎖的先后順序來。 Node exclusive lock(獨占鎖) ReentrantLock ReentrantLock實現了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會被掛起或...

    Yangyang 評論0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - Condition 實現原理

    摘要:實現原理是通過基于單鏈表的條件隊列來管理等待線程的。中斷在轉移到同步隊列期間或之后發生,此時表明有線程正在調用轉移節點。在該種中斷模式下,再次設置線程的中斷狀態。 1. 簡介 Condition是一個接口,AbstractQueuedSynchronizer 中的ConditionObject內部類實現了這個接口。Condition聲明了一組等待/通知的方法,這些方法的功能與Objec...

    leone 評論0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - Condition 實現原理

    摘要:實現原理是通過基于單鏈表的條件隊列來管理等待線程的。中斷在轉移到同步隊列期間或之后發生,此時表明有線程正在調用轉移節點。在該種中斷模式下,再次設置線程的中斷狀態。 1. 簡介 Condition是一個接口,AbstractQueuedSynchronizer 中的ConditionObject內部類實現了這個接口。Condition聲明了一組等待/通知的方法,這些方法的功能與Objec...

    李世贊 評論0 收藏0

發表評論

0條評論

zhunjiee

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<