可中斷獲取鎖與超時等待獲取鎖源碼分析


可中斷式獲取鎖

  • 可響應中斷式鎖可調用方法lock.lockInterruptibly();該方法的底層會調用AQS的acqireInterruptibly方法;

acquireInterruptibly()方法:

public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    //這裏會先檢查是否有被中斷,如果有則拋出一箇中斷異常
    //否則嘗試去獲取同步狀態,成功直接退出,失敗則進入doAcquireInterruptibly(arg)方法
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

doAcquireInterruptibly()方法:

  • 如果當前線程的前驅節點爲隊頭時,嘗試獲取同步狀態
    若獲取成功則將隊頭節點出隊,當前線程置爲持有鎖線程,並將隊頭指針指向當前線程所封裝的節點,否則不斷自旋直到獲取成功或者線程被中斷
/**
 * Acquires in exclusive interruptible mode.
 * @param arg the acquire argument
 */
private void doAcquireInterruptibly(int arg)
    throws InterruptedException {
        //嘗試將節點插入到同步隊列
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            //取當前節點的前驅節點
            final Node p = node.predecessor();
            //如果前驅節點爲頭結點,且成功獲取同步狀態則將持有鎖線程
            //置爲當前線程,並將隊頭節點出隊
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            //獲取同步狀態失敗,線程進入等待狀態等待獲取獨佔式
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                //線程被阻塞時若檢測到中斷拋出中斷異常後退出。
                throw new InterruptedException();
        }
    } finally {
        //獲取同步狀態失敗將當前節點取消
        if (failed)
            cancelAcquire(node);
    }
}

超時等待獲取鎖(tryAcquireNanos()方法)

  • 調用lock.tryLock(timeout,TimeUnit)方式
  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  • 超時等待鎖的返回條件:
    1. 在指定時間內獲取到鎖
    2. 在指定時間內沒有獲取到鎖
    3. 在指定時間內被中斷
public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
  • 該方法調用AQS的tryAcquireNanos()方法:先判斷是否被中斷,然後嘗試獲取同步狀態
    如果成功則直接返會,否則進入到doAcquireNanos()方法:
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquire(arg) ||
        doAcquireNanos(arg, nanosTimeout);
}

doAcquireNanos()方法:

/**
 * Acquires in exclusive timed mode.
 *
 * @param arg the acquire argument
 * @param nanosTimeout max wait time
 * @return {@code true} if acquired
 */
private boolean doAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    //如果設置的時間不合法,直接返回
    if (nanosTimeout <= 0L)
        return false;
    //計算截止時間
    final long deadline = System.nanoTime() + nanosTimeout;
    //嘗試將當前節點插入到同步隊列
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            //當前線程獲得鎖出隊
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return true;
            }
            //重新計算超時時間
            nanosTimeout = deadline - System.nanoTime();
            //如果超時直接返回
            if (nanosTimeout <= 0L)
                return false;
            //線程阻塞等待
            if (shouldParkAfterFailedAcquire(p, node) &&
                nanosTimeout > spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            //若線程被中斷則拋出中斷異常
            if (Thread.interrupted())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}


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