多線程(三):ReentrantLock NonfairSync FairSync

結構

首先看看ReentranLock結構,它實現Lock接口,也擁有Sync ,NonfairSync, FairSync三個內部類,

( NonfairSync, FairSync   )-----繼承-------> Sync ------繼承-------> AbstractQueuedSynchronizer

NonfairSync ,FairSync 重寫了AQS 的 tryAcquire 

構造方式:

public ReentrantLock() {
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

ReentrantLock 默認實現非公平鎖,構造爲true時才構造公平鎖

Nonfair.lock

ReentrantLock.class

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



AQS.class

public final void acquire(int arg) {
// 嘗試獲取不成功 並且加入隊發現線程被打斷了,
// 設置當前線程打斷了
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

非公平鎖上鎖時,調用sync的acquire,sync的acquire實則繼承AQS的acquire方法,

獲取:先嚐試獲取,不成功再加入等待隊

最終的實現tryAcquire 就是ReetranLock.Sync.nonfairTryAcquire方法

 final boolean nonfairTryAcquire(int acquires) {
            // 當前線程
            final Thread current = Thread.currentThread();
            // 獲取AQS狀態值
            int c = getState();
            if (c == 0) {
                // 沒鎖,cas ,直接獲取鎖
                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;
        }

加入等待隊列

acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
Node.EXCLUSIVE = null 標記 獨佔模式節點

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

         for (;;) {
            //獲取尾節點
            Node oldTail = tail;

            if (oldTail != null) {
            // 尾節點不爲空 證明當前隊列有值


                // 將尾節點(tail)設置爲node的前節點
                node.setPrevRelaxed(oldTail);

                // cas 將尾節點設置爲node
                if (compareAndSetTail(oldTail, node)) {
                    // 之前尾節點的下一個節點指向 node
                    oldTail.next = node;
                    // 處理成功 返回node
                    return node;
                }
            } else {
            // 隊列爲空 初始化隊
                initializeSyncQueue();
            }
        }
    }


 // 初始化同步隊列
    private final void initializeSyncQueue() {
        Node h;
        if (HEAD.compareAndSet(this, null, (h = new Node())))
            tail = h;
    }
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;
        }
    }



    // 節點的上一個節點
    final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }



        // 嘗試失敗後是否阻塞

        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;
    }

從源碼中看出 作者編程一般使用 && 來判斷是否進行下一步

用死循環遞歸

 

1.嘗試獲取 成功就結束了,不成功:加入隊列;

2.先加入等待隊列,

1)隊列操作:

隊列有節點,直接入隊,將當天節點設置爲尾節點,

隊列沒節點,初始化一個空隊列,首尾相同 head = tail ,進行上面操作。

2)再次嘗試,設置等待狀態 ,去除取消的節點,判斷當前被打斷

再次嘗試:如果這是前面沒有節點了,也就是頭節點是當前節點的前置節點,再次嘗試獲取

設置等待狀態(判斷前節點狀態):等待觸發-->判斷被打斷;取消--->設置節點的前節點是未取消的前面節點;初始或其他狀態-->將前節點設置爲等待觸發 ,然後在進行上面操作循環。

判斷被打斷:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章