ReentrantLock 的公平鎖與非公平鎖

公平鎖與非公平鎖是指,多個線程在獲取同一把鎖的策略,是按照先到先得仍是直接競爭。先到先得的策略就是公平鎖,排隊對全部的線程來講是公平的,直接競爭的策略則是非公平的。java

image.png
在調用ReenterantLock的構造函數的時候決定是構造一個公平鎖仍是非公平鎖。node

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

來看獲取鎖的過程:函數

ReentrantLock lock = new ReentrantLock();
lock.lock();

點進去看,是調用了sync的lock方法
image.png
這裏就是對應了咱們的公平鎖/非公平鎖的lock方法。
image.png
到這裏沒有什麼大的差別,無非是非公平鎖多了一個步驟。cas操做去嘗試獲取鎖,成功了設置owner線程爲當前線程。失敗了再調用acquire方法獲取鎖。
那接下來繼續看兩種鎖的acquire方法,兩個方法都來到了aqs的acquire方法。
image.pngui

點進去那些方法,全部方法都進入了aqs實現的步驟,只有tryAcquire方法有不一樣的實現。
image.png
進去看,公平鎖只是多了 hasQueuedPredecessors這個方法。spa

image.png
公平鎖線程

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {    // 當前鎖的狀態是無所狀態
        if (!hasQueuedPredecessors() &&    // 判斷隊列中是否有前驅節點,若果有前驅節點,就不會執行下面的代碼,不會去獲取鎖
            compareAndSetState(0, acquires)) {    // 使用cas嘗試獲取鎖
            setExclusiveOwnerThread(current);    // 設置owner線程爲當前線程
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {    // 持有鎖的線程爲當前線程
        int nextc = c + acquires;    
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);    // 更新sate(重入鎖的原理)
        return true;
    }
    return false;
}

以上分析了公平鎖和非公平鎖的一個不一樣。
下面以非公平鎖分析加鎖的過程
獲取鎖的過程:code

/**
 * Performs lock.  Try immediate barge, backing up to normal * acquire on failure. */final void lock() {
    if (compareAndSetState(0, 1))   // 嘗試用cas來獲取鎖(改變state的值)
        setExclusiveOwnerThread(Thread.currentThread());    // 設置owner線程爲當前線程
    else
 acquire(1); // 若是鎖的狀態不爲0,被其餘線程持有,嘗試獲取鎖
}
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

tryAcquire(arg)方法是嘗試獲取鎖。orm

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

原理和上面公平鎖的tryAcquire方法一致。隊列

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))方法:
addWaiter方法:get

private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
 Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

建立一個node,入隊,並返回該Node
acquireQueued再嘗試獲取鎖


非公平鎖解鎖的過程:

public final boolean release(int arg) {
    if (tryRelease(arg)) {  // 嘗試去釋放鎖
        Node h = head;
        if (h != null && h.waitStatus != 0) // h頭結點爲空,而且state不等於0
            unparkSuccessor(h); // 去喚醒後繼節點
        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);      // 設置owner線程爲空
    }
    setState(c);            // 更新state
    return free;
}
相關文章
相關標籤/搜索