AbstractQueuedSynchronizer- 獨占鎖實現(xiàn)細節(jié)

1-ReentrantLock

ReentrantLock是獨占鎖,而且內部可以是公平鎖,非公平鎖;
公平鎖:
公平鎖:加鎖錢需要檢查是否還有在排隊(等待)的線程,優(yōu)先排隊的

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

非公平鎖:
加鎖時無需考慮之前是否有線程等待,直接嘗試獲取鎖,獲取失敗會自動追加到同步隊列隊尾

   final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

2 上鎖流程

2.1 acquire方法

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

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

    static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

涉及簡單方法分析:

  • tryAcquire方法直接拋出異常,也即是自定義獨占鎖必須實現(xiàn)這個方法;
  • selfInterrupt 獲取鎖的線程進行中斷操作,這個并不一定導致線程停止

2.2 addWaiter方法

整體來說,就是加入一個節(jié)點到隊列尾部;如果未初始化隊列,則進行初始化(延時策略)

private Node addWaiter(Node mode) {
        Node node = new Node(mode);

        for (;;) {
            Node oldTail = tail;
            if (oldTail != null) {
                U.putObject(node, Node.PREV, oldTail);
                if (compareAndSetTail(oldTail, node)) {
                    oldTail.next = node;
                    return node;
                }
            } else {
                initializeSyncQueue();
            }
        }
    }

  1. 首先生成一個Node節(jié)點,這個節(jié)點nextWaiter為空(Node.EXCLUSIVE為空對象);獨占鎖的nextWaiter為空
  2. for循環(huán)自旋
  3. 如果隊列未進行初始化,則initializeSyncQueue進行初始化,如果不成功,繼續(xù)此步驟直至成功
  4. 加入隊列尾部

2.3 acquireQueued方法

    final boolean acquireQueued(final Node node, int arg) {
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
    }

  • for循環(huán)自旋;如果其是頭節(jié)點下的第一個節(jié)點,如果嘗試獲取資源成功,則進行設置為隊列頭,釋放之前頭節(jié)點,并返回false;返回false,則意味線程跳出自旋,可以繼續(xù)執(zhí)行
  • 如果不是鎖等待隊列的第二個,則執(zhí)行shouldParkAfterFailedAcquire方法,如果為true,繼續(xù)執(zhí)行parkAndCheckInterrupt方法
  • shouldParkAfterFailedAcquire方法執(zhí)行后,返回false會去掉取消的節(jié)點,之后如果未有狀態(tài)變化(比如外部取消線程,打斷等操作),則會返回true,可以詳細看下面方法源碼

2.4 shouldParkAfterFailedAcquire方法

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
        }
        return false;
    }

  • 如果node 前一個節(jié)點pred節(jié)點已經是等待喚醒狀態(tài),則返回true,表示當線線程應該被暫停
  • 如果node前一個節(jié)點狀態(tài)大于0,暫時好像只有取消狀態(tài)的,則找到一個狀態(tài)小于等于0的,并是node為其后繼節(jié)點,則尋找過程中的節(jié)點都會被移除隊列,返回false
  • 如果node前一個節(jié)點已經是小于等于0了,這時把前一個幾點的狀態(tài)置為等待喚醒-1,返回false

2.6 parkAndCheckInterrupt方法

   private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

  • 暫停正在執(zhí)行的線程,并返回打斷狀態(tài)

3 釋放鎖流程

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

  • tryRelease需要自定義實現(xiàn),否則直接拋出異常
  • 如果頭節(jié)點不是正在運行狀態(tài),則解鎖頭節(jié)點線程,釋放鎖成功
  • 否則不需要釋放鎖,或者釋放失?。ò凑照?,在鎖等待隊列中,獨占鎖/條件鎖,都會為signal狀態(tài),為共享鎖為signal或者PROPAGATE狀態(tài))

3.1 unparkSuccessor方法

    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

  • CAS操作,釋放頭節(jié)點狀態(tài)設置為0
  • 從頭結點后尋找一個節(jié)點不為空,且節(jié)點為0的節(jié)點,釋放此節(jié)點的線程(上述獲取資源時,進行自旋,去除頭結點后的取消的節(jié)點后的第一個節(jié)點才可以獲取資源)

4 獨占鎖原理小結

  • nextWaiter為空
  • 排隊等鎖的隊列,頭優(yōu)先獲取資源(對于非公平鎖,新獲取未排隊的線程也會獲取鎖);嘗試獲取資源的線程排隊到隊尾
  • 獲取資源失敗的線程,被掛起;持有線程執(zhí)行完畢,則頭節(jié)點的下一個節(jié)點恢復執(zhí)行,嘗試獲取資源(非公平鎖,會和新獲取鎖未排隊進來的線程爭奪鎖)成功后繼續(xù)執(zhí)行其任務,失敗線程掛起,并置為等待喚醒狀態(tài)
  • 可重入鎖,即當前線程再次獲取資源,狀態(tài)+1,釋放資源狀態(tài)-1,如果是0,則是當前線程完全釋放了資源,其它排隊線程可以獲取資源了;代碼如下:非公平鎖的代碼

   final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

參考

AbstractQueuedSynchronizer原理解析

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容