91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Future?cancel迷惑性boolean入參源碼分析

發布時間:2023-03-01 10:10:18 來源:億速云 閱讀:143 作者:iii 欄目:開發技術

本篇內容介紹了“Future cancel迷惑性boolean入參源碼分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

前言

當我們使用線程池submit一個任務后,會返回一個Future,而在Future接口中存在一個cancel方法,來幫助我們取消掉任務。

但是cancel方法有一個boolean類型的入參,比較迷惑,之前也了解過該入參true 和 false的區別。

/**
 * Attempts to cancel execution of this task.  This attempt will
 * fail if the task has already completed, has already been cancelled,
 * or could not be cancelled for some other reason. If successful,
 * and this task has not started when {@code cancel} is called,
 * this task should never run.  If the task has already started,
 * then the {@code mayInterruptIfRunning} parameter determines
 * whether the thread executing this task should be interrupted in
 * an attempt to stop the task.
 *
 * <p>After this method returns, subsequent calls to {@link #isDone} will
 * always return {@code true}.  Subsequent calls to {@link #isCancelled}
 * will always return {@code true} if this method returned {@code true}.
 *
 * @param mayInterruptIfRunning {@code true} if the thread executing this
 * task should be interrupted; otherwise, in-progress tasks are allowed
 * to complete
 * @return {@code false} if the task could not be cancelled,
 * typically because it has already completed normally;
 * {@code true} otherwise
 */
boolean cancel(boolean mayInterruptIfRunning);

上面是cancel方法的接口定義,當然英文看著麻煩,咱直接翻譯成看得懂的~

cancel方法,會嘗試取消任務的執行,但如果任務已經完成、已經取消或其他原因無法取消,則嘗試取消任務失敗。

如果取消成功,并且在取消時

  • 該任務還未執行,那么這個任務永遠不會執行。

  • 如果該任務已經啟動,那么會根據cancelboolean入參來決定是否中斷執行此任務的線程來停止任務。

通過注釋我們大致能了解到cancel的一個作用,但是還不夠細致,接下來我們通過源碼解讀詳細的帶大家了解一下~

FutureTask任務狀態認知

首先,我們先了解下FutureTask中對任務狀態的定義

在使用線程池submit后,實際上是返回的一個FutureTask,而FutureTask中對于任務定義了以下狀態,并且在注釋中,也定義了狀態的流轉過程~

/**
 * Possible state transitions:
 * NEW -> COMPLETING -> NORMAL
 * NEW -> COMPLETING -> EXCEPTIONAL
 * NEW -> CANCELLED
 * NEW -> INTERRUPTING -> INTERRUPTED
 */
private volatile int state;
private static final int NEW          = 0;
private static final int COMPLETING   = 1;
private static final int NORMAL       = 2;
private static final int EXCEPTIONAL  = 3;
private static final int CANCELLED    = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED  = 6;

但是通過對上面狀態定義的了解,我們可以發現,在FutureTask中并沒有一個表明任務處于執行中的一個狀態!

直接看FutureTaskrun方法源碼

public void run() {
    if (state != NEW ||
        !RUNNER.compareAndSet(this, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 執行任務
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                // 執行異常
                setException(ex);
            }
            if (ran)
                // 正常執行完畢
                set(result);
        }
    } finally {
      //... 省略
    }
}

protected void setException(Throwable t) {
  if (STATE.compareAndSet(this, NEW, COMPLETING)) {
    outcome = t;
    STATE.setRelease(this, EXCEPTIONAL); // final state
    finishCompletion();
  }
}

protected void set(V v) {
  if (STATE.compareAndSet(this, NEW, COMPLETING)) {
    outcome = v;
    STATE.setRelease(this, NORMAL); // final state
    finishCompletion();
  }
}

通過上面源碼,我們也能了解到

  • 當任務正常執行完畢時,任務狀態流轉: NEW -> COMPLETING -> NORMAL

  • 任務執行異常時,任務狀態流轉: NEW -> COMPLETING -> EXCEPTIONAL

所以,當任務剛創建,或者是任務在執行過程中,任務的狀態都是NEW

cancel源碼分析

此時再來分析cancel源碼

public boolean cancel(boolean mayInterruptIfRunning) {
    // NEW為新建或者運行態
    // 1. 此時任務已經不是NEW,說明要么是完成要么是異常,取消不了,所以返回false
    // 2. 此時任務還是NEW,如果我們傳入true,則CAS標記任務為INTERRUPTING,否則是CANCELLED
    // 防止并發取消任務,CAS只會有一個線程成功,其余線程失敗
    if (!(state == NEW && STATE.compareAndSet
          (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    
        // 傳入true,則打斷該任務的執行線程
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally {
                // 比較任務狀態為INTERRUPTED
                STATE.setRelease(this, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();
    }
    return true;
}

通過對FutureTask任務狀態的認知,再結合對cancel源碼的分析

我們可以總結出以下結論

當任務已經完成或者異常時,無法取消任務

任務處于新建或者運行狀態時

cancel方法入參傳入true

將任務狀態NEW -> INTERRUPTING -> INTERRUPTED,并打斷執行該任務的線程

cancel方法入參傳入false

將任務狀態NEW -> CANCELLED

但有個問題,傳入false只是將狀態從NEW變成CANCELLED嘛,這好像沒啥用啊?

當然不是,此時我們需要再回頭看看FutureTaskrun方法

public void run() {
    if (state != NEW ||
        !RUNNER.compareAndSet(this, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                // 執行異常
                setException(ex);
            }
            if (ran)
                // 正常執行完畢
                set(result);
        }
    } finally {
      //... 省略
    }
}

run方法開頭我們可以看到,如果任務的狀態不是NEW,那么會直接return,不執行任務

那此時再想想傳入false將任務狀態從NEW -> CANCELLED,是不是當任務還沒有開始執行時,我們cancel(false)就可以取消掉未執行的任務了~

總結

通過上面的源碼解讀,我們大致能了解了cancel的機制,但是我們還是完善的總結一下

任務如果不是NEW狀態是不會執行的

cancel取消任務會改變任務的狀態

  • 如果傳入true, 則將任務狀態NEW -> INTERRUPTING -> INTERRUPTED,并打斷執行該任務的線程

  • 如果傳入false,將任務狀態NEW -> CANCELLED

傳入false只能取消還未執行的任務

傳入true,能取消未執行的任務,能打斷正在執行的任務

擴展知識點

cancel源碼中,我們可以看到finally中會去調用finishCompletion

那么,finishCompletion是干啥的呢?

private void finishCompletion() {
    // assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        // 原子性將WAITERS設置為null
        if (WAITERS.weakCompareAndSet(this, q, null)) {
          
            // 遍歷WAITERS,將阻塞的線程都喚醒
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null;
                q = next;
            }
            break;
        }
    }

    // 擴展方法,交給自己實現
    done();

    callable = null;
}

大家可以想想,當我們submit一個任務時,一般情況下都會需要去獲取他的返回值,會調用get方法進行阻塞獲取。在FutureTask中,會維護一條鏈表,該鏈表記錄了等待獲取該任務返回值被阻塞的線程,在調用get方法時,會將組裝waiters鏈表。所以,當我們取消一個任務時,是不是也應該去將阻塞等待獲取該任務的所有線程進行喚醒,而finishCompletion方法就是做這個事情的~

“Future cancel迷惑性boolean入參源碼分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

方山县| 定安县| 遂宁市| 稷山县| 汉中市| 北海市| 彭州市| 鲁甸县| 广宁县| 汉沽区| 梓潼县| 绩溪县| 榕江县| 濮阳市| 吉安县| 龙山县| 朝阳区| 台州市| 大埔县| 洪江市| 云浮市| 合作市| 确山县| 彭泽县| 霞浦县| 鄂伦春自治旗| 乌鲁木齐县| 托克托县| 全椒县| 米易县| 托里县| 栖霞市| 邢台县| 宜宾县| 克山县| 西乡县| 古田县| 望谟县| 招远市| 峨山| 城步|