ReentrantLock 基於源碼瞭解工作流程

ReentrantLock和synchronized在jdk1.8版本後性能相差無幾,甚至synchronized小優,但是synchronized不支持中斷和超時,也就是說通過synchronized一旦被阻塞住,如果一直無法獲取到所資源就會一直被阻塞,即使中斷也沒用,這對併發系統的性能影響太大了;Lock支持中斷和超時、還支持嘗試機制獲取鎖,對synchronized進行了很好的擴展,所以從靈活性上Lock是明顯優於synchronized的

基本方法
// 構造方法
// boolean fair 是否爲公平鎖
ReentrantLock(boolean fair)

// 嘗試拿鎖,拿不到阻塞等待
void lock();
// 釋放鎖
void unlock();
// 等待拿鎖的時間可被中斷
void lockInterruptibly() throws InterruptedException; 
// 嘗試拿鎖,不等待
boolean tryLock();
// 嘗試拿鎖,等待timeout時間
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException;

公平鎖

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

public final void acquire(int arg) {
    // 首先嚐試拿鎖
    if (!tryAcquire(arg) &&
        // addWaiter 拿鎖失敗時候 加入(創建)請求隊列
        // acquireQueued 在一個死循環中 判斷是否是隊列頭 並嘗試拿鎖,否則阻塞 LockSupport.park(this)
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
//嘗試拿鎖
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) { 
        // 當前鎖狀態爲空閒
        // hasQueuedPredecessors 當前線程是否需要排隊(公平鎖) true: 需要, false: 不需要
        if (!hasQueuedPredecessors() &&
            // 通過 CAS 拿鎖
            compareAndSetState(0, acquires)) {
            // 成功拿到鎖之後設置當前持有鎖的線程爲當前線程
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 當前有線程持有鎖
    // 判斷當前持有鎖的線程是否是當前線程
    else if (current == getExclusiveOwnerThread()) {
        // 是當前線程 則 c + 1 (可重入)
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc); // 設置當前鎖狀態
        return true;
    }
    return false;
}

// 將當前線程加入請求隊列
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;
}
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        // 死循環
        for (;;) { 
            // 拿到當前線程的prev
            final Node p = node.predecessor();
            // 若 prev 是頭部 則嘗試拿鎖
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            // 判斷當前線程請求狀態是否應該 park
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt()) // 阻塞 LockSupport.park(this);
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
釋放鎖
public final boolean release(int arg) {
    // 釋放鎖
    if (tryRelease(arg)) {
        Node h = head;
        // 釋放成功後 將請求隊列的 head 節點 unpark 喚醒
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
protected final boolean tryRelease(int releases) {
    // 鎖定次數 - 1
    int c = getState() - releases;
    // 判斷當前線程是否是當前持有鎖的線程
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 如果 c == 0 則 當前鎖爲空閒狀態
    if (c == 0) {
        free = true;
        // 設置持有鎖的線程爲空
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

非公平鎖

final void lock() {
    // 嘗試拿鎖  (插隊)
    if (compareAndSetState(0, 1))
        // 拿鎖成功 設置當前持有鎖的線程爲當前線程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 此方法與公平鎖使用同一個方法
        acquire(1);
}
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章