1. 程式人生 > >ReentrantLock非公平鎖理解

ReentrantLock非公平鎖理解

一直理解,ReentrantLock支援公不鎖與非公平鎖,公平鎖即先申請先得到鎖,非公平鎖相把,即鎖釋放時,所有執行緒同時競爭鎖。今天讀了ReentrantLock原始碼,發現自己解決的非公平鎖與原始碼實現不同。非公平鎖並不是所有執行緒同時競爭鎖,而是新執行緒第一次競爭鎖時,和執行緒步佇列中的第一個執行緒進行競爭鎖,從而達到非公平。 開始懷疑人生了,這也不是決對的非公平,於是上網查了一下,從一個部落格下面,有一段描述,說的非常清楚


通過分析ReentrantLock中的公平鎖和非公平鎖的實現,其中tryAcquire是公平鎖和非公平鎖實現的區別,下面的兩種型別的鎖的tryAcquire的實現,從中我們可以看出在公平鎖中,每一次的tryAcquire都會檢查CLH佇列中是否仍有前驅的元素,如果仍然有那麼繼續等待,通過這種方式來保證先來先服務的原則;而非公平鎖,首先是檢查並設定鎖的狀態,這種方式會出現即使佇列中有等待的執行緒,但是新的執行緒仍然會與排隊執行緒中的對頭執行緒競爭(但是排隊的執行緒是先來先服務的),所以新的執行緒可能會搶佔已經在排隊的執行緒的鎖,這樣就無法保證先來先服務,但是已經等待的執行緒們是仍然保證先來先服務的,所以總結一下公平鎖和非公平鎖的區別:

1、公平鎖能保證:老的執行緒排隊使用鎖,新執行緒仍然排隊使用鎖。

2、非公平鎖保證:老的執行緒排隊使用鎖;但是無法保證新執行緒搶佔已經在排隊的執行緒的鎖


以下為類AbstractQueuedSynchronizer的方法隊,ReentrantLock中的非公平鎖獲取失敗的執行緒進行執行緒同步佇列後,依靠下面的方法進行自旋再次獲取鎖,可以看到只有一個條件會從方法中返回,就是前驅節點是頭點結點並且成功獲取鎖。

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                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);
        }
    }