欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的FutureTask用法和原理解析

 更新時間:2024年10月31日 14:30:46   作者:seven97_top  
本文深入剖析了Java并發(fā)編程中的FutureTask,包括其與Callable和Future的關(guān)系、使用方法以及內(nèi)部實現(xiàn)原理,FutureTask是Future的基礎(chǔ)實現(xiàn),用于處理異步計算結(jié)果,提供了任務(wù)執(zhí)行結(jié)果獲取和任務(wù)取消等方法

前言

Callable、Future和FutureTask是jdk1.5,java.util.concurrent包提供的異步框架

這里先講一下什么是異步?異步是指起多個線程,多個線程之間互不干擾,各自執(zhí)行各自的任務(wù),在代碼中可能書寫順序有先有后,但有可能寫在后面的線程會比寫在前面的線程先執(zhí)行任務(wù),異步對應(yīng)并行的概念,常見的異步操作有線程池、Callable、completeFuture等。

同步是多線程里針對競爭現(xiàn)象的一個處理,競爭是指同一時刻有多個線程訪問臨界資源,可能會引發(fā)程序執(zhí)行錯誤的結(jié)果,同步就是保證某一時刻僅能有一個線程訪問臨界資源,同步對應(yīng)串行的概念,常見的同步操作有synchronized關(guān)鍵字、Lock、線程變量、Atomic原子類等。

什么時候需要異步?比如要執(zhí)行一個任務(wù),該任務(wù)執(zhí)行完后會返回一個結(jié)果供其他任務(wù)使用,但是該任務(wù)很耗時,如果我們把程序設(shè)計成串行執(zhí)行,先執(zhí)行這個耗時任務(wù),等他結(jié)束后再把執(zhí)行結(jié)果給下一個任務(wù)使用,這樣會耗時,且在這個任務(wù)執(zhí)行期間,其他任務(wù)都被阻塞了。那么就可以把程序設(shè)計成異步,起一個線程執(zhí)行這個耗時任務(wù),此外主線程做其他事情,等這個耗時任務(wù)執(zhí)行完畢后,主線程再把結(jié)果拿到,使用這個結(jié)果繼續(xù)做其他事情,這樣在這個耗時任務(wù)執(zhí)行的過程中,主線程可以去做其他事情而不是等他執(zhí)行完,這樣效率會很高,因此異步編程在提高并發(fā)量上使用廣泛。

Callable接口

先看Callable接口的源碼:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

首先是注解是函數(shù)式接口,意味著可以用lambda表達(dá)式更簡潔地使用它。Callable是個泛型接口,只有一個方法call,該方法返回類型就是傳遞進(jìn)來的V類型。call方法還支持拋出異常.

與Callable對應(yīng)的是Runnable接口,實現(xiàn)了這兩個接口的類都可以當(dāng)做線程任務(wù)遞交給線程池執(zhí)行,Runnable接口的源碼如下:

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

既然實現(xiàn)了這兩個接口的類都可以當(dāng)做線程任務(wù),那么這兩個接口有什么區(qū)別呢?

  • Runnable接口是java1.1就有的,Callable接口是java1.5才有的,可以認(rèn)為Callable接口是升級版的Runnable接口;
  • Runnable接口里線程任務(wù)是在run方法里寫的,Callable接口里線程任務(wù)是在call方法里寫;
  • Callable接口的任務(wù)執(zhí)行后會有返回值,Runnable接口的任務(wù)無返回值(void);
  • Callable接口的call方法支持拋出異常,Runnable接口的run方法不可以;
  • 加入線程池運行,Runnable使用ExecutorService的execute方法,Callable使用ExecutorService的submit方法;
  • 運行Callable任務(wù)可以拿到一個Future對象,表示異步計算的結(jié)果。Future對象封裝了檢查計算是否完成、檢索計算的結(jié)果的方法,而Runnable接口沒有。

Callable使用ExecutorService的submit方法,這里看一下ExecutorService接口里的submit方法的重載情況:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

常用的是第一個和第三個,這兩個方法分別提交實現(xiàn)了Callable接口的類和實現(xiàn)了Runnable接口的類作為線程任務(wù),返回異步計算結(jié)果Future,F(xiàn)uture里面封裝了一些實用方法可以對異步計算結(jié)果進(jìn)行進(jìn)一步處理。

Future接口

Future接口代表異步計算的結(jié)果,通過Future接口提供的方法可以查看異步計算是否執(zhí)行完成,或者等待執(zhí)行結(jié)果并獲取執(zhí)行結(jié)果,同時還可以取消執(zhí)行。Future接口的定義如下:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

下面對這五個方法介紹:

  • cancel():用來取消異步任務(wù)的執(zhí)行。如果異步任務(wù)已經(jīng)完成或者已經(jīng)被取消,或者由于某些原因不能取消,則會返回false。如果任務(wù)還沒有被執(zhí)行,則會返回true并且異步任務(wù)不會被執(zhí)行。如果任務(wù)已經(jīng)開始執(zhí)行了但是還沒有執(zhí)行完成,若mayInterruptIfRunning為true,則會立即中斷執(zhí)行任務(wù)的線程并返回true,若mayInterruptIfRunning為false,則會返回true且不會中斷任務(wù)執(zhí)行線程。
  • isCanceled():判斷任務(wù)是否被取消,如果任務(wù)在結(jié)束(正常執(zhí)行結(jié)束或者執(zhí)行異常結(jié)束)前被取消則返回true,否則返回false。
  • isDone():判斷任務(wù)是否已經(jīng)完成,如果完成則返回true,否則返回false。需要注意的是:任務(wù)執(zhí)行過程中發(fā)生異常、任務(wù)被取消也屬于任務(wù)已完成,也會返回true。
  • get():獲取任務(wù)執(zhí)行結(jié)果,如果任務(wù)還沒完成則會阻塞等待直到任務(wù)執(zhí)行完成。如果任務(wù)被取消則會拋出CancellationException異常,如果任務(wù)執(zhí)行過程發(fā)生異常則會拋出ExecutionException異常,如果阻塞等待過程中被中斷則會拋出InterruptedException異常。
  • get(long timeout,Timeunit unit):帶超時時間的get()版本,如果阻塞等待過程中超時則會拋出TimeoutException異常。

注意這里兩個get方法都會拋出異常。

FutureTask

Future是一個接口,而FutureTask 為 Future 提供了基礎(chǔ)實現(xiàn),如獲取任務(wù)執(zhí)行結(jié)果(get)和取消任務(wù)(cancel)等。如果任務(wù)尚未完成,獲取任務(wù)執(zhí)行結(jié)果時將會阻塞。一旦執(zhí)行結(jié)束,任務(wù)就不能被重啟或取消(除非使用runAndReset執(zhí)行計算)。FutureTask 常用來封裝 Callable 和 Runnable,也可以作為一個任務(wù)提交到線程池中執(zhí)行。除了作為一個獨立的類之外,此類也提供了一些功能性函數(shù)供我們創(chuàng)建自定義 task 類使用。FutureTask 的線程安全由CAS來保證。

源碼如下:

public class FutureTask<V> implements RunnableFuture<V> {
...
}

FutureTask類實現(xiàn)的是RunnableFuture <V>接口,該接口的源碼如下:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

該接口繼承了Runnable接口和Future接口,因此FutureTask類既可以當(dāng)做線程任務(wù)遞交給線程池執(zhí)行,又能當(dāng)Callable任務(wù)的計算結(jié)果。

Future VS FutureTask

Future與FutureTask的區(qū)別:

  • Future是一個接口,F(xiàn)utureTask是一個實現(xiàn)類;
  • 使用Future初始化一個異步任務(wù)結(jié)果一般需要搭配線程池的submit,且submit方法有返回值;而初始化一個FutureTask對象需要傳入一個實現(xiàn)了Callable接口的類的對象,直接將FutureTask對象submit給線程池,無返回值;
  • Future + Callable獲取結(jié)果需要Future對象的get,而FutureTask獲取結(jié)果直接用FutureTask對象的get方法即可。

使用示例

Callable + Future

實現(xiàn)Callable接口創(chuàng)建一個異步任務(wù)的類,在主線程中起一個線程池執(zhí)行異步任務(wù),然后在主線程里拿到異步任務(wù)的返回結(jié)果。

import java.util.concurrent.*;
public class AsynDemo {
    public static void main(String[] args) {
        // 初始化線程池
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        // 初始化線程任務(wù)
        MyTask myTask = new MyTask(5);
        // 向線程池遞交線程任務(wù)
        Future<Integer> result = threadPool.submit(myTask);
        // 主線程休眠2秒,模擬主線程在做其他的事情
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 主線程獲取異步任務(wù)的執(zhí)行結(jié)果
        try {
            System.out.println("異步線程任務(wù)執(zhí)行結(jié)果 " + result.get());
            System.out.println("檢查異步線程任務(wù)是否執(zhí)行完畢 " + result.isDone());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    // 靜態(tài)內(nèi)部類,實現(xiàn)Callable接口的任務(wù)類
    static class MyTask implements Callable<Integer> {
        private int num;
        public MyTask(int num) {
            this.num = num;
        }
        @Override
        public Integer call() throws Exception {
            for (int i = 1; i < 10; ++i) {
                this.num *= i;
            }
            return this.num;
        }
    }
}

執(zhí)行結(jié)果如下:

異步線程任務(wù)執(zhí)行結(jié)果 1814400
檢查異步線程任務(wù)是否執(zhí)行完畢 true

Callable + FutureTask

???????

要做的事情跟4.1一樣。

import java.util.concurrent.*;
public class FutureTaskDemo {
    public static void main(String[] args) {
        // 初始化線程池
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        // 初始化MyTask實例
        MyTask myTask = new MyTask(5);
        // 用MyTask的實例對象初始化一個FutureTask對象
        FutureTask<Integer> myFutureTask = new FutureTask<>(myTask);
        // 向線程池遞交線程任務(wù)
        threadPool.submit(myFutureTask);
        // 關(guān)閉線程池
        threadPool.shutdown();
        // 主線程休眠2秒,模擬主線程在做其他的事情
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 主線程獲取異步任務(wù)的執(zhí)行結(jié)果
        try {
            System.out.println("異步線程任務(wù)執(zhí)行結(jié)果 " + myFutureTask.get());
            System.out.println("檢查異步線程任務(wù)是否執(zhí)行完畢 " + myFutureTask.isDone());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    // 靜態(tài)內(nèi)部類,實現(xiàn)Callable接口的任務(wù)類
    static class MyTask implements Callable<Integer> {
        private int num;
        public MyTask(int num) {
            this.num = num;
        }
        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName() + " 正在執(zhí)行異步任務(wù)");
            for (int i = 1; i < 10; ++i) {
                this.num *= i;
            }
            return this.num;
        }
    }
}

執(zhí)行結(jié)果與4.1一樣。

底層源碼解析

FutureTask類關(guān)系

可以看到,FutureTask實現(xiàn)了RunnableFuture接口,則RunnableFuture接口繼承了Runnable接口和Future接口,所以FutureTask既能當(dāng)做一個Runnable直接被Thread執(zhí)行,也能作為Future用來得到Callable的計算結(jié)果。

核心屬性

//內(nèi)部持有的callable任務(wù),運行完畢后置空
private Callable<V> callable;
//從get()中返回的結(jié)果或拋出的異常
private Object outcome; // non-volatile, protected by state reads/writes
//運行callable的線程
private volatile Thread runner;
//使用Treiber棧保存等待線程
private volatile WaitNode waiters;
//任務(wù)狀態(tài)
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;

其中需要注意的是state是volatile類型的,也就是說只要有任何一個線程修改了這個變量,那么其他所有的線程都會知道最新的值。7種狀態(tài)具體表示:

  • NEW:表示是個新的任務(wù)或者還沒被執(zhí)行完的任務(wù)。這是初始狀態(tài)。
  • COMPLETING:任務(wù)已經(jīng)執(zhí)行完成或者執(zhí)行任務(wù)的時候發(fā)生異常,但是任務(wù)執(zhí)行結(jié)果或者異常原因還沒有保存到outcome字段(outcome字段用來保存任務(wù)執(zhí)行結(jié)果,如果發(fā)生異常,則用來保存異常原因)的時候,狀態(tài)會從NEW變更到COMPLETING。但是這個狀態(tài)會時間會比較短,屬于中間狀態(tài)。
  • NORMAL:任務(wù)已經(jīng)執(zhí)行完成并且任務(wù)執(zhí)行結(jié)果已經(jīng)保存到outcome字段,狀態(tài)會從COMPLETING轉(zhuǎn)換到NORMAL。這是一個最終態(tài)。
  • EXCEPTIONAL:任務(wù)執(zhí)行發(fā)生異常并且異常原因已經(jīng)保存到outcome字段中后,狀態(tài)會從COMPLETING轉(zhuǎn)換到EXCEPTIONAL。這是一個最終態(tài)。
  • CANCELLED:任務(wù)還沒開始執(zhí)行或者已經(jīng)開始執(zhí)行但是還沒有執(zhí)行完成的時候,用戶調(diào)用了cancel(false)方法取消任務(wù)且不中斷任務(wù)執(zhí)行線程,這個時候狀態(tài)會從NEW轉(zhuǎn)化為CANCELLED狀態(tài)。這是一個最終態(tài)。
  • INTERRUPTING: 任務(wù)還沒開始執(zhí)行或者已經(jīng)執(zhí)行但是還沒有執(zhí)行完成的時候,用戶調(diào)用了cancel(true)方法取消任務(wù)并且要中斷任務(wù)執(zhí)行線程但是還沒有中斷任務(wù)執(zhí)行線程之前,狀態(tài)會從NEW轉(zhuǎn)化為INTERRUPTING。這是一個中間狀態(tài)。
  • INTERRUPTED:調(diào)用interrupt()中斷任務(wù)執(zhí)行線程之后狀態(tài)會從INTERRUPTING轉(zhuǎn)換到INTERRUPTED。這是一個最終態(tài)。 有一點需要注意的是,所有值大于COMPLETING的狀態(tài)都表示任務(wù)已經(jīng)執(zhí)行完成(任務(wù)正常執(zhí)行完成,任務(wù)執(zhí)行異常或者任務(wù)被取消)。

各個狀態(tài)之間的可能轉(zhuǎn)換關(guān)系如下圖所示:

構(gòu)造函數(shù)

FutureTask(Callable<V> callable)

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

這個構(gòu)造函數(shù)會把傳入的Callable變量保存在this.callable字段中,該字段定義為private Callable<V> callable;用來保存底層的調(diào)用,在被執(zhí)行完成以后會指向null,接著會初始化state字段為NEW。

FutureTask(Runnable runnable, V result)

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

這個構(gòu)造函數(shù)會把傳入的Runnable封裝成一個Callable對象保存在callable字段中,同時如果任務(wù)執(zhí)行成功的話就會返回傳入的result。這種情況下如果不需要返回值的話可以傳入一個null。

順帶看下Executors.callable()這個方法,這個方法的功能是把Runnable轉(zhuǎn)換成Callable,代碼如下:

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
       throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

可以看到這里采用的是適配器模式,調(diào)用RunnableAdapter<T>(task, result)方法來適配,實現(xiàn)如下:

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

這個適配器很簡單,就是簡單的實現(xiàn)了Callable接口,在call()實現(xiàn)中調(diào)用Runnable.run()方法,然后把傳入的result作為任務(wù)的結(jié)果返回。

在new了一個FutureTask對象之后,接下來就是在另一個線程中執(zhí)行這個Task,無論是通過直接new一個Thread還是通過線程池,執(zhí)行的都是run()方法,接下來就看看run()方法的實現(xiàn)。

核心方法 - run()

public void run() {
    //新建任務(wù),CAS替換runner為當(dāng)前線程
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     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);//設(shè)置執(zhí)行結(jié)果
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);//處理中斷邏輯
    }
}

說明:

運行任務(wù),如果任務(wù)狀態(tài)為NEW狀態(tài),則利用CAS修改為當(dāng)前線程。執(zhí)行完畢調(diào)用set(result)方法設(shè)置執(zhí)行結(jié)果。set(result)源碼如下:

protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();//執(zhí)行完畢,喚醒等待線程
    }
}

???????首先利用cas修改state狀態(tài)為COMPLETING,設(shè)置返回結(jié)果,然后使用 lazySet(UNSAFE.putOrderedInt)的方式設(shè)置state狀態(tài)為NORMAL。結(jié)果設(shè)置完畢后,調(diào)用finishCompletion()方法喚醒等待線程,源碼如下:

private void finishCompletion() {
    // assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {//移除等待線程
            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; // unlink to help gc
                q = next;
            }
            break;
        }
    }
    //任務(wù)完成后調(diào)用函數(shù),自定義擴展
    done();
    callable = null;        // to reduce footprint
}

???????回到run方法,如果在 run 期間被中斷,此時需要調(diào)用handlePossibleCancellationInterrupt方法來處理中斷邏輯,確保任何中斷(例如cancel(true))只停留在當(dāng)前run或runAndReset的任務(wù)中,源碼如下:

???????
private void handlePossibleCancellationInterrupt(int s) {
    //在中斷者中斷線程之前可能會延遲,所以我們只需要讓出CPU時間片自旋等待
    if (s == INTERRUPTING)
        while (state == INTERRUPTING)
            Thread.yield(); // wait out pending interrupt
}

???????核心方法 - get()

//獲取執(zhí)行結(jié)果
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

說明:FutureTask 通過get()方法獲取任務(wù)執(zhí)行結(jié)果。如果任務(wù)處于未完成的狀態(tài)(state <= COMPLETING),就調(diào)用awaitDone方法(后面單獨講解)等待任務(wù)完成。任務(wù)完成后,通過report方法獲取執(zhí)行結(jié)果或拋出執(zhí)行期間的異常。report源碼如下:

//返回執(zhí)行結(jié)果或拋出異常
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

???????核心方法 - awaitDone(boolean timed, long nanos)

private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    WaitNode q = null;
    boolean queued = false;
    for (;;) {//自旋
        if (Thread.interrupted()) {//獲取并清除中斷狀態(tài)
            removeWaiter(q);//移除等待WaitNode
            throw new InterruptedException();
        }
        int s = state;
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;//置空等待節(jié)點的線程
            return s;
        }
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        else if (q == null)
            q = new WaitNode();
        else if (!queued)
            //CAS修改waiter
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
        else if (timed) {
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q);//超時,移除等待節(jié)點
                return state;
            }
            LockSupport.parkNanos(this, nanos);//阻塞當(dāng)前線程
        }
        else
            LockSupport.park(this);//阻塞當(dāng)前線程
    }
}

說明:awaitDone用于等待任務(wù)完成,或任務(wù)因為中斷或超時而終止。返回任務(wù)的完成狀態(tài)。函數(shù)執(zhí)行邏輯如下:

如果線程被中斷,首先清除中斷狀態(tài),調(diào)用removeWaiter移除等待節(jié)點,然后拋出InterruptedException。removeWaiter源碼如下:

private void removeWaiter(WaitNode node) {
    if (node != null) {
        node.thread = null;//首先置空線程
        retry:
        for (;;) {          // restart on removeWaiter race
            //依次遍歷查找
            for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                s = q.next;
                if (q.thread != null)
                    pred = q;
                else if (pred != null) {
                    pred.next = s;
                    if (pred.thread == null) // check for race
                        continue retry;
                }
                else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,q, s)) //cas替換
                    continue retry;
            }
            break;
        }
    }
}
  • 如果當(dāng)前狀態(tài)為結(jié)束狀態(tài)(state>COMPLETING),則根據(jù)需要置空等待節(jié)點的線程,并返回 Future 狀態(tài);
  • 如果當(dāng)前狀態(tài)為正在完成(COMPLETING),說明此時 Future 還不能做出超時動作,為任務(wù)讓出CPU執(zhí)行時間片;
  • 如果state為NEW,先新建一個WaitNode,然后CAS修改當(dāng)前waiters;
  • 如果等待超時,則調(diào)用removeWaiter移除等待節(jié)點,返回任務(wù)狀態(tài);如果設(shè)置了超時時間但是尚未超時,則park阻塞當(dāng)前線程;
  • 其他情況直接阻塞當(dāng)前線程。

核心方法 - cancel(boolean mayInterruptIfRunning)

public boolean cancel(boolean mayInterruptIfRunning) {
    //如果當(dāng)前Future狀態(tài)為NEW,根據(jù)參數(shù)修改Future狀態(tài)為INTERRUPTING或CANCELLED
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        if (mayInterruptIfRunning) {//可以在運行時中斷
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();//移除并喚醒所有等待線程
    }
    return true;
}

說明:嘗試取消任務(wù)。如果任務(wù)已經(jīng)完成或已經(jīng)被取消,此操作會失敗。

  • 如果當(dāng)前Future狀態(tài)為NEW,根據(jù)參數(shù)修改Future狀態(tài)為INTERRUPTING或CANCELLED。
  • 如果當(dāng)前狀態(tài)不為NEW,則根據(jù)參數(shù)mayInterruptIfRunning決定是否在任務(wù)運行中也可以中斷。中斷操作完成后,調(diào)用finishCompletion移除并喚醒所有等待線程

到此這篇關(guān)于Java中的FutureTask:用法和原理 的文章就介紹到這了,更多相關(guān)Java FutureTask 用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java深入講解AWT實現(xiàn)事件處理流程

    Java深入講解AWT實現(xiàn)事件處理流程

    AWT的事件處理是一種委派式事件處理方式:普通組件(事件源)將整個事件處理委托給特定的對象(事件監(jiān)聽器);當(dāng)該事件源發(fā)生指定的事件時,就通知所委托的事件監(jiān)聽器,由事件監(jiān)聽器來處理這個事件
    2022-04-04
  • Spring Boot + Mybatis多數(shù)據(jù)源和動態(tài)數(shù)據(jù)源配置方法

    Spring Boot + Mybatis多數(shù)據(jù)源和動態(tài)數(shù)據(jù)源配置方法

    最近做項目遇到這樣的應(yīng)用場景,項目需要同時連接兩個不同的數(shù)據(jù)庫A, B,并且它們都為主從架構(gòu),一臺寫庫,多臺讀庫。下面小編給大家?guī)砹薙pring Boot + Mybatis多數(shù)據(jù)源和動態(tài)數(shù)據(jù)源配置方法,需要的朋友參考下吧
    2018-01-01
  • java微信支付功能實現(xiàn)源碼

    java微信支付功能實現(xiàn)源碼

    這篇文章主要給大家介紹了關(guān)于java微信支付功能實現(xiàn)源碼的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Spring5+SpringMvc+Hibernate5整合的實現(xiàn)

    Spring5+SpringMvc+Hibernate5整合的實現(xiàn)

    這篇文章主要介紹了Spring5+SpringMvc+Hibernate5整合的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • IntelliJ IDEA失焦自動重啟服務(wù)的解決方法

    IntelliJ IDEA失焦自動重啟服務(wù)的解決方法

    在使用 IntelliJ IDEA運行 SpringBoot 項目時,你可能會遇到一個令人困擾的問題,一旦你的鼠標(biāo)指針離開當(dāng)前IDE窗口,點擊其他位置時, IDE 窗口會失去焦點,你的 SpringBoot 服務(wù)就會自動重啟,所以本文給大家介紹了IntelliJ IDEA失焦自動重啟服務(wù)的解決方法
    2023-10-10
  • Java實現(xiàn)JS中的escape和UNescape代碼分享

    Java實現(xiàn)JS中的escape和UNescape代碼分享

    在PHP和Python中都有類似JS中的escape和UNescape函數(shù)的功能,那么Java語言中到底有沒有類似的方法呢?本文就來介紹一下Java實現(xiàn)JS中的escape和UNescape轉(zhuǎn)碼方法,需要的朋友可以參考下
    2017-09-09
  • Java編寫簡單計算器的完整實現(xiàn)過程

    Java編寫簡單計算器的完整實現(xiàn)過程

    這篇文章主要給大家介紹了關(guān)于Java編寫簡單計算器的完整實現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Mybatis 實現(xiàn)一個搜索框?qū)Χ鄠€字段進(jìn)行模糊查詢

    Mybatis 實現(xiàn)一個搜索框?qū)Χ鄠€字段進(jìn)行模糊查詢

    這篇文章主要介紹了Mybatis 實現(xiàn)一個搜索框?qū)Χ鄠€字段進(jìn)行模糊查詢,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Java獲取登錄用戶的IP地址示例代碼

    Java獲取登錄用戶的IP地址示例代碼

    在開發(fā)中我們經(jīng)常需要獲取用戶IP地址,通過地址來實現(xiàn)一些功能,下面這篇文章主要給大家介紹了關(guān)于Java獲取登錄用戶的IP地址的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • Java中常用的設(shè)計模式之工廠模式詳解

    Java中常用的設(shè)計模式之工廠模式詳解

    這篇文章主要為大家詳細(xì)介紹了Java中常用的設(shè)計模式之工廠模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02

最新評論