Android Handler機(jī)制系列文章整體內(nèi)容如下:
- Android Handler機(jī)制1之Thread
- Android Handler機(jī)制2之ThreadLocal
- Android Handler機(jī)制3之SystemClock類
- Android Handler機(jī)制4之Looper與Handler簡(jiǎn)介
- Android Handler機(jī)制5之Message簡(jiǎn)介與消息對(duì)象對(duì)象池
- Android Handler機(jī)制6之MessageQueue簡(jiǎn)介
- Android Handler機(jī)制7之消息發(fā)送
- Android Handler機(jī)制8之消息的取出與消息的其他操作
- Android Handler機(jī)制9之Handler的Native實(shí)現(xiàn)前奏之Linux IO多路復(fù)用
- Android Handler機(jī)制10之Handdler的Native實(shí)現(xiàn)Native的實(shí)現(xiàn)
- Android Handler機(jī)制11之Handler機(jī)制總結(jié)
- Android Handler機(jī)制12之Callable、Future和FutureTask
- Android Handler機(jī)制13之AsyncTask源碼解析
本片文章的主要內(nèi)容如下:
- 1、概述
- 2、Callable
- 3、Future
- 4、FutureTask
- 5、總結(jié)
一、概述
- Java從發(fā)布的一個(gè)版本開始就可以很方便地編寫多線程的應(yīng)用程序,并在設(shè)計(jì)中引入異步處理。創(chuàng)建線程有兩種方式,一種是直接繼承Thread,另外一種就是實(shí)現(xiàn)Runnable接口。Thread類、Runnable接口和Java內(nèi)存管理模型使得多線程編程簡(jiǎn)單直接。但是大家知道Thread和Runnable接口都不允許聲明檢查性異常,也不能返定義返回值。沒有返回值這點(diǎn)稍微有點(diǎn)麻煩。
- 不能聲明拋出檢查型異常則更麻煩一些。public void run()方法契約意味著你必須捕獲并處理檢查型異常。即使你小心地保存了異常信息(在捕獲異常時(shí))以便稍后檢查, 但也不能保證這個(gè)類(Runnnable)的所有使用者都讀取這個(gè)異常信息。你也可以修改Runnable實(shí)現(xiàn)的getter,讓他們都能拋出任務(wù)執(zhí)行中的異常。但這種方法除了繁瑣也不是十分安全可靠,你不能強(qiáng)迫使用者調(diào)用這些方法,程序員很可能會(huì)調(diào)用join()方法等待線程結(jié)束后就不管了。
- 但是現(xiàn)在不用擔(dān)心了,以上問題終于在1.5中解決了。Callable接口和Future接口接口的引入以及他們對(duì)線程池的支持優(yōu)雅地解決了這個(gè)兩個(gè)問題。
二、Callable
(一) Runnable
說到Callable就不能不說下java.lang.Runnable,它是一個(gè)接口,它只聲明了一個(gè)run()方法,由于這個(gè)run()方法的返回值是void的,所以在執(zhí)行完任務(wù)之后無法返回任何結(jié)果。
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();
}
(二) Callable
Callable位于java.util.concurrent包下,它也是一個(gè)接口,在它里面也只聲明了一個(gè)方法,只不過這個(gè)方法叫做call()
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* <p>The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
* <p>The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@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;
}
可以看到,這一個(gè)泛型的接口,call()函數(shù)返回的類型就是傳遞進(jìn)來的V類型。
(三) Callable的類注釋
為了讓我們更好的理解Callable,還是從類的注釋開始,翻譯如下:
- 有執(zhí)行結(jié)果的,并且可以引發(fā)異常的任務(wù)
它的實(shí)現(xiàn)類需要去實(shí)現(xiàn)沒有參數(shù)的的方法,即call()方法- Callable有點(diǎn)類似于Runnable接口,因?yàn)樗鼈兌际窃O(shè)計(jì)成被線程去執(zhí)行的可執(zhí)行代碼的實(shí)例。由于Runnable是沒有返回值的,并且不能拋出一個(gè)檢查出的異常。
- Executors類包含方法可以使得Callable轉(zhuǎn)化成其他普通形式。
(四)、 Runnable和Callable的區(qū)別:
- 1、Runnable是Java 1.1有的,而Callable是1.5之后才加上去的
- 2、Callable規(guī)定的方法是call(),Runnable規(guī)定的方法是run()
- 3、Callable的任務(wù)執(zhí)行后可返回值,而Runnable的任務(wù)是不能返回(因?yàn)槭莢oid)
- 4、call()方法是可以拋出異常的,而run()方法不可以
- 5、運(yùn)行Callable任務(wù)可以拿到一個(gè)Future對(duì)象,表示異步計(jì)算的結(jié)果,它提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并檢索計(jì)算的結(jié)果,通過Future對(duì)象可以了解任務(wù)的執(zhí)行情況,可取消任務(wù)的執(zhí)行,還可獲取執(zhí)行結(jié)果
- 6、加入線程池運(yùn)行,Runnable使用ExecutorService的execute()方法,Callable使用submit()方法
三、Future
(一) Future類詳解
Future就是對(duì)于具體的Runnable或者Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消、查詢是否完成、獲取結(jié)果。必要時(shí)可以通過get方法獲取執(zhí)行結(jié)果,該方法會(huì)阻塞知道任務(wù)返回結(jié)果。Future類位于java.util.concurrent包下,它是一個(gè)接口:
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;
}
在Future接口中聲明了5個(gè)方法,下面依次解釋下每個(gè)方法的作用:
- boolean cancel(boolean mayInterruptIfRunning):方法用來取消任務(wù),如果取消任務(wù)成功則返回true,如果取消任務(wù)失敗則返回false。參數(shù)mayInterruptIfRunning表示是否允許取消正在執(zhí)行卻沒有執(zhí)行完畢的任務(wù),如果設(shè)置為true,則表示可以取消正在執(zhí)行過程中任務(wù)。如果任務(wù)已經(jīng)完成,則無論mayInterruptIfRunning為true還是false,此方法肯定返回false,即如果取消已完成的任務(wù)會(huì)返回false;如果任務(wù)正在執(zhí)行,若mayInterruptIfRunning設(shè)置為true,則返回true,若mayInterruptIfRunning設(shè)置為false,則返回false;如果任務(wù)還沒有執(zhí)行,則無論mayInterruptIfRunning為true還是false,肯定返回true。
- boolean isCancelled():表示任務(wù)是否被取消成功,如果在任務(wù)正常完成之前取消成功則返回true.
- isDone():方法表示任務(wù)是否已經(jīng)完成,若任務(wù)完成,則返回true。
- V get():方法用來獲取執(zhí)行結(jié)果,這個(gè)方法會(huì)產(chǎn)生阻塞,會(huì)一直等到任務(wù)執(zhí)行完畢才返回
- V get(long timeout, TimeUnit unit):用來獲取執(zhí)行結(jié)果,如果在指定時(shí)間內(nèi),還沒獲取到結(jié)果,就直接返回null。
總結(jié)一下,F(xiàn)uture提供了三種功能:
- 判斷任務(wù)是否完成
- 能夠中斷任務(wù)
- 能夠獲取任務(wù)的執(zhí)行結(jié)果
(二) Future類注釋
- Future可以表示異步計(jì)算的結(jié)果。Future提供一個(gè)方法用來檢查這個(gè)計(jì)算是否已經(jīng)完成,還提供一個(gè)方法用來檢索計(jì)算結(jié)果。get()方法可以獲取計(jì)算結(jié)果,這個(gè)方法里面可能產(chǎn)生阻塞,如果產(chǎn)生了阻塞了,就阻塞到計(jì)算結(jié)束。cancel()方法可以取消執(zhí)行。還有一些方法可以用來確定任務(wù)是否已經(jīng)完成、是否已經(jīng)取消成功了。如果任務(wù)已經(jīng)執(zhí)行完畢,則是不能取消的。如果你想使用Future并且,希望它是不可撤銷的,同時(shí)不關(guān)心執(zhí)行的結(jié)果,可以聲明Future的泛型,并且基礎(chǔ)任務(wù)返回值結(jié)果為null。
- 使用示例
class App { ExecutorService executor = ... ArchiveSearcher searcher = ... void showSearch(final String target) throws InterruptedException { Future<String> future = executor.submit(new Callable<String>() { public String call() { return searcher.search(target); } }); displayOtherThings(); // do other things while searching try { displayText(future.get()); // use future } catch (ExecutionException ex) { cleanup(); return; } } }FutureTask是Future的具體實(shí)現(xiàn)類,同時(shí)也實(shí)現(xiàn)了Runnable。所以FutureTask可以被Executor執(zhí)行。例如Executor的submit方法可以換成如下寫法
FutureTask<String> future = new FutureTask<>(new Callable<String>() { public String call() { return searcher.search(target); }}); executor.execute(future);內(nèi)存一致性效應(yīng):如果想在另一個(gè)線程調(diào)用 Future.get()方法,則在調(diào)用該方法之前應(yīng)該先執(zhí)行其自己的操作。
(三) boolean cancel(boolean mayInterruptIfRunning)方法注釋
翻譯如下:
嘗試去關(guān)閉正在執(zhí)行的任務(wù),如果任務(wù)已經(jīng)完成,或者任務(wù)已經(jīng)被取消,或者任務(wù)因?yàn)槟撤N原因而無法被取消,則關(guān)閉事失敗。當(dāng)這個(gè)任務(wù)還沒有被執(zhí)行,則調(diào)用此方法會(huì)成功,并且這個(gè)任務(wù)將來不會(huì)被執(zhí)行。如果任務(wù)已經(jīng)開始了,mayInterruptIfRunning這個(gè)入?yún)Q定是否應(yīng)該中斷該任務(wù)。這個(gè)方法被執(zhí)行返回后,再去調(diào)用isDone()方法,將一直返回true。如果調(diào)用這個(gè)方法后返回true,再去調(diào)用isCancelled()方法,則isCancelled()方法一直返回true。mayInterruptIfRunning這個(gè)參數(shù)表示的是該任務(wù)的線程是否可以被中斷,true表示可以中斷,如果這個(gè)任務(wù)不能被取消,則返回false,而大多數(shù)這種情況是任務(wù)已完成。
上面已經(jīng)提到了Future只是一個(gè)接口,所以是無法直接用來創(chuàng)建對(duì)象使用的,在注釋里面推薦使用FutureTask,那我們就來看下FutureTask
四、FutureTask
FutureTask.java源碼地址
我們先來看一下FutureTask的實(shí)現(xiàn):
(一)、RunnableFuture
通過代碼我們知道
public class FutureTask<V> implements RunnableFuture<V>
說明FutureTask類實(shí)現(xiàn)了RunnableFuture接口,我們看一下RunnableFuture接口
/**
* A {@link Future} that is {@link Runnable}. Successful execution of
* the {@code run} method causes completion of the {@code Future}
* and allows access to its results.
* @see FutureTask
* @see Executor
* @since 1.6
* @author Doug Lea
* @param <V> The result type returned by this Future's {@code get} method
*/
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
通過代碼我知道RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實(shí)現(xiàn)了RunnableFuture接口。所以它既可以作為Runnable被線程執(zhí)行,也可以作為Future得到Callable的返回值
(二)、FutureTask的類注釋
/**
* A cancellable asynchronous computation. This class provides a base
* implementation of {@link Future}, with methods to start and cancel
* a computation, query to see if the computation is complete, and
* retrieve the result of the computation. The result can only be
* retrieved when the computation has completed; the {@code get}
* methods will block if the computation has not yet completed. Once
* the computation has completed, the computation cannot be restarted
* or cancelled (unless the computation is invoked using
* {@link #runAndReset}).
*
* <p>A {@code FutureTask} can be used to wrap a {@link Callable} or
* {@link Runnable} object. Because {@code FutureTask} implements
* {@code Runnable}, a {@code FutureTask} can be submitted to an
* {@link Executor} for execution.
*
* <p>In addition to serving as a standalone class, this class provides
* {@code protected} functionality that may be useful when creating
* customized task classes.
*
* @since 1.5
* @author Doug Lea
* @param <V> The result type returned by this FutureTask's {@code get} methods
*/
為了更好的理解作者設(shè)計(jì),先來看下類注釋,翻譯如下:
- 一個(gè)可以取消的異步執(zhí)行,這個(gè)類是Future的基礎(chǔ)實(shí)現(xiàn)類,提供一下方法,比如可以去開啟和關(guān)閉執(zhí)行,查詢是否已經(jīng)執(zhí)行完畢,以及檢索計(jì)算的結(jié)果。這個(gè)執(zhí)行結(jié)果只能等執(zhí)行完畢才能獲取,如果還未執(zhí)行完畢則處于阻塞狀態(tài)。除非調(diào)用runAndReset()方法,否則一旦計(jì)算完畢后則無法重啟啟動(dòng)或者取消。
- Callable或者Runnable可以包裝FutureTask,由于FutureTask實(shí)現(xiàn)Runnable,所以在Executor可以執(zhí)行FutureTask
- 除了可以作為一個(gè)獨(dú)立的類外,F(xiàn)utureTask還提供一些protected方法,這樣在自定義任務(wù)類是,就會(huì)很方便。
(三)、FutureTask的結(jié)構(gòu)
結(jié)構(gòu)如下圖

繼承關(guān)系如下:

(四)、靜態(tài)final類WaitNode
/**
* Simple linked list nodes to record waiting threads in a Treiber
* stack. See other classes such as Phaser and SynchronousQueue
* for more detailed explanation.
*/
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
先翻譯一下注釋
精簡(jiǎn)版的鏈表結(jié)構(gòu),其中每一個(gè)節(jié)點(diǎn)代表堆棧中等待的線程。如果想了解更多的詳細(xì)說明,請(qǐng)參考其他類比如Phaser和SynchronousQueue
結(jié)構(gòu)如下圖

再來看下構(gòu)造函數(shù)和成員變量
- thread:代表等待的線程
- next:代表下一個(gè)節(jié)點(diǎn),通過這個(gè)節(jié)點(diǎn)我們也能退出這個(gè)鏈表是單向鏈表
- 構(gòu)造函數(shù):無參的構(gòu)造函數(shù)里面將thread設(shè)置為當(dāng)前線程。
總結(jié):
WaitNode就是一個(gè)鏈表結(jié)構(gòu),用于記錄等待當(dāng)前FutureTask結(jié)果的線程。
(五)、FutureTask的狀態(tài)
FutureTask一共有7種狀態(tài),代碼如下:
/*
* Revision notes: This differs from previous versions of this
* class that relied on AbstractQueuedSynchronizer, mainly to
* avoid surprising users about retaining interrupt status during
* cancellation races. Sync control in the current design relies
* on a "state" field updated via CAS to track completion, along
* with a simple Treiber stack to hold waiting threads.
*
* Style note: As usual, we bypass overhead of using
* AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
*/
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* 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;
老規(guī)矩先來翻譯一下注釋,我們看到注釋有兩部分,我們依次翻譯如下:
- 上半部分注釋:
修訂說明:和之前版本的AbstractQueuedSynchronizer不同,主要是為了避免令人驚訝的用戶在取消競(jìng)爭(zhēng)遷建保留中斷的狀態(tài)。在當(dāng)前設(shè)計(jì)中,同步的控制是通過CAS中的更新字段——"state"來完成跟蹤的。并且通過一個(gè)Treiber堆棧來保存這些等待的線程。風(fēng)格筆記(筆者注:這個(gè)真心不知道怎么翻譯,誰知道請(qǐng)?jiān)谙旅媪粞?:和往常一樣,我們直接使用不安全的內(nèi)在函數(shù), 并且忽略使用AtomicXFieldUpdaters的開銷。
簡(jiǎn)單的說就是,F(xiàn)utureTask中使用state表示任務(wù)狀態(tài),state變更由CAS操作保證原子性。
- 下半部分注釋:
這個(gè)任務(wù)的運(yùn)行狀態(tài),最初是NEW狀態(tài),在調(diào)用set()方法或者setException()方法或者cancel()方法后,運(yùn)行的狀態(tài)就變?yōu)榻K端的狀態(tài)。在運(yùn)行期間,如果計(jì)算出結(jié)果后,狀態(tài)變更為COMPLETING,如果通過調(diào)用cancel(true)安全的中斷運(yùn)行,則狀態(tài)變更為INTERRUPTING。由于值是唯一且不能被進(jìn)一步修改,所以從中間狀態(tài)到最終狀態(tài)的轉(zhuǎn)化是有序的。- 可能的狀態(tài)變更流程
- NEW -> COMPLETING -> NORMAL
- NEW -> COMPLETING -> EXCEPTIONAL
- NEW -> CANCELLED
- NEW -> INTERRUPTING -> INTERRUPTED
上面翻譯我感覺不是很好,用白話解釋一下:
FutureTask對(duì)象初始化時(shí),在構(gòu)造器把state設(shè)置為NEW,之后狀態(tài)變更依據(jù)具體執(zhí)行情況來定。
- 任務(wù)執(zhí)行正常,并且還沒結(jié)束,state為COMPLETING,代表任務(wù)正在執(zhí)行即將完成,接下來很快會(huì)被設(shè)置為NORMAL或者EXCEPTIONAL,這取決于調(diào)用Runnable中的call()方法是否拋出異常,沒有異常則是NORMAL,拋出異常是EXCEPTIONAL。
- 任務(wù)提交后、任務(wù)結(jié)束前取消任務(wù),都有可能變?yōu)镃ANCELLED或者INTERRUPTED。在調(diào)用cancel(boolean) 是,如果傳入false表示不中斷線程,state會(huì)變成CANCELLED,如果傳入true,則state先變?yōu)?br> INTERRUPTING,中斷完成后,變?yōu)镮NTERRUPTED。
總結(jié)一下就是:FutureTask的狀態(tài)變化過程為,以下4種情況:
- 任務(wù)正常執(zhí)行并返回: NEW -> COMPLETING -> NORMAL
- 任務(wù)執(zhí)行中出現(xiàn)異常:NEW -> COMPLETING -> EXCEPTIONAL
- 任務(wù)執(zhí)行過程中被取消,并且不中斷線程:NEW -> CANCELLED
- 任務(wù)執(zhí)行過程中被取消,并且中斷線程:NEW -> INTERRUPTING -> INTERRUPTED
那我們就簡(jiǎn)單的解釋下幾種狀態(tài)
- NEW:任務(wù)初始化狀態(tài)
- COMPLETING:任務(wù)正在完成狀態(tài)(任務(wù)已經(jīng)執(zhí)行完成,但是結(jié)果還沒有賦值給outcome)
- NORMAL:任務(wù)完成(結(jié)果已經(jīng)賦值給outcome)
- EXCEPTIONAL:任務(wù)執(zhí)行異常
- CANCELLED:任務(wù)被取消
- INTERRUPTING:任務(wù)被中斷中
- INTERRUPTED:任務(wù)被中斷
(六)、FutureTask的成員變量
/** The underlying callable; nulled out after running */
private Callable<V> callable;
/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run() */
private volatile Thread runner;
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
- callable:任務(wù)具體執(zhí)行體,具體要做的事
- outcome:任務(wù)的執(zhí)行結(jié)果,get()方法的返回值
- runner:任務(wù)的執(zhí)行線程
- waiters:獲取任務(wù)結(jié)果的等待線程(是一個(gè)鏈?zhǔn)搅斜?
(七)、FutureTask的構(gòu)造函數(shù)
FutureTask有兩個(gè)構(gòu)造函數(shù)
分別是FutureTask(Callable<V> callable)和FutureTask(Runnable runnable, V result),那我們來依次分析
1、構(gòu)造函數(shù) FutureTask(Callable<V> callable)
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
老規(guī)矩先翻譯一下注釋:
創(chuàng)建一個(gè)FutureTask,并在將來執(zhí)行的時(shí)候,運(yùn)行傳入的Callable。
看下代碼,我們知道:
- 1、通過代碼我們知道如果傳入的Callable為空直接拋出異常,說明構(gòu)造時(shí)傳入的Callable不能為空。
- 2、設(shè)置當(dāng)前狀態(tài)為NEW。
所以總結(jié)一句話就是,通過傳入Callable來構(gòu)造一個(gè)FutureTask。
2、構(gòu)造函數(shù) FutureTask(Runnable runnable, V result)
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don't need a particular result, consider using
* constructions of the form:
* {@code Future<?> f = new FutureTask<Void>(runnable, null)}
* @throws NullPointerException if the runnable is null
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
老規(guī)矩先翻譯一下注釋:
創(chuàng)建一個(gè)FutureTask,并在將來執(zhí)行的時(shí)候,運(yùn)行傳入的Runnable,并且將成功完成后的結(jié)果返給傳入的result。
看下代碼,我們知道:
- 1、先通過調(diào)用Executors的callable(Runnable, T)方法返回的Callable
- 2、將上面返回的Callable指向本地變量callable
- 3、設(shè)置當(dāng)前狀態(tài)為NEW。
所以總結(jié)一句話就是,通過傳入Runnable來構(gòu)造一個(gè)任務(wù)
這里順帶說下Executors.callable(runnable, result)方法的內(nèi)部實(shí)現(xiàn)
2.1、Executors.callable(Runnable, T)
/**
* Returns a {@link Callable} object that, when
* called, runs the given task and returns the given result. This
* can be useful when applying methods requiring a
* {@code Callable} to an otherwise resultless action.
* @param task the task to run
* @param result the result to return
* @param <T> the type of the result
* @return a callable object
* @throws NullPointerException if task null
*/
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
方法內(nèi)部很簡(jiǎn)單,就是new了一個(gè)RunnableAdapter并返回,那我們來看下RunnableAdapterr適配器
/**
* A callable that runs given task and returns given result.
*/
private static final class RunnableAdapter<T> implements Callable<T> {
private final Runnable task;
private final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
通過上面代碼我們知道:
- RunnableAdapter是FutureTask的一個(gè)靜態(tài)內(nèi)部類并且實(shí)現(xiàn)了Callable,也就是說RunnableAdapter是Callable子類。
- call方法實(shí)現(xiàn)代碼是,執(zhí)行Runnable的run方法,并返回構(gòu)造函數(shù)傳入的result參數(shù)。
這里實(shí)際上是將一個(gè)Runnable對(duì)象偽裝成一個(gè)Callable對(duì)象,是適配器對(duì)象。
3、構(gòu)造函數(shù)總結(jié)
通過分析上面兩個(gè)構(gòu)造函數(shù),我們知道無論采用第一個(gè)構(gòu)造函數(shù),還是第二個(gè)構(gòu)造函數(shù),其結(jié)果都是給本地變量callable初始化賦值,所以說FutureTask最終都是執(zhí)行Callable類型的任務(wù)。然后設(shè)置狀態(tài)為NEW。
(八)、FutureTask的幾個(gè)核心方法
FutureTask有幾個(gè)核心方法:
- public void run():表示任務(wù)的執(zhí)行
- public V get()和public V get(long timeout, TimeUnit unit):表示獲取任務(wù)的結(jié)果
- public boolean cancel(boolean mayInterruptIfRunning):表示取消任務(wù)
那我們就依次來看下
1、run()方法
/**
* 判斷任務(wù)的狀態(tài)是否是初始化的狀態(tài)
* 判斷執(zhí)行任務(wù)的線程對(duì)象runner是否為null,為空就將當(dāng)前執(zhí)行線程賦值給runner屬性
* 不為空說明應(yīng)有線程準(zhǔn)備執(zhí)行這個(gè)任務(wù)了
*/
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
// 任務(wù)狀態(tài)時(shí)NEW,并且callable不為空,則執(zhí)行任務(wù)
// 如果認(rèn)為被cancel了,callable會(huì)被置空
Callable<V> c = callable;
if (c != null && state == NEW) {
V result; // 結(jié)果的變量
boolean ran; // 執(zhí)行完畢的變量
try {
// 執(zhí)行任務(wù)并返回結(jié)果
result = c.call();
ran = true;
} catch (Throwable ex) {
// 執(zhí)行異常
result = null;
ran = false;
setException(ex);
}
if (ran)
//任務(wù)執(zhí)行完畢就設(shè)置結(jié)果
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
// 將執(zhí)行任務(wù)的執(zhí)行線程清空
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
//判斷線程的狀態(tài)
handlePossibleCancellationInterrupt(s);
}
}
通過上面代碼和注釋我們知道run方法內(nèi)部的流程如下:
- 第一步:檢查當(dāng)前任務(wù)是否是NEW以及runner是否為空,這一步是防止任務(wù)被取消
- 第二步:double-check任務(wù)狀態(tài)和state
- 第三步:執(zhí)行業(yè)務(wù)邏輯,也就是c.call()方法被執(zhí)行
- 第四步:如果業(yè)務(wù)邏輯異常,則調(diào)用setException方法將異常對(duì)象賦值給outcome,并更新state的值
- 第五步:如果業(yè)務(wù)正常,則調(diào)用set方法將執(zhí)行結(jié)果賦給outcome,并更新state值。
1.1、Unsafe類
Java不能夠直接訪問操作系統(tǒng)底層,而是通過本地方法來訪問。Unsafe提供了硬件級(jí)別的原子訪問,主要提供以下功能:
- 分配釋放內(nèi)存
- 定位某個(gè)字段的內(nèi)存位置
- 掛起一個(gè)線程和恢復(fù),更多的是通過LockSupport來訪問。park和unpark
- CAS操作,比較一個(gè)對(duì)象的某個(gè)位置的內(nèi)存值是否與期望值一致。
主要方法是compareAndSwap()
1.1.1UNSAFE.compareAndSwapObject(this,runnerOffset,null, Thread.currentThread())方法
UNSAFE.compareAndSwapObject(this,RUNNER,null, Thread.currentThread())這行代碼什么意思?
compareAndSwapObject可以通過反射,根據(jù)偏移量去修改對(duì)象,第一個(gè)參數(shù)表示要修改的對(duì)象,第二個(gè)表示偏移量,第三個(gè)參數(shù)用于和偏移量對(duì)應(yīng)的值進(jìn)行比較,第四個(gè)參數(shù)表示如何偏移量對(duì)應(yīng)的值和第三個(gè)參數(shù)一樣時(shí)要把偏移量設(shè)置成的值。
翻譯成白話文就是:
如果this對(duì)象的RUNNER偏移地址的值是null,那就把它設(shè)置為Thread.currentThread()。
上面提到了一個(gè)概念是RUNNER,那這個(gè)RUNNER 是什么東東?
我們?cè)谠创a中找到
// Unsafe mechanics
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long STATE;
private static final long RUNNER;
private static final long WAITERS;
static {
try {
STATE = U.objectFieldOffset
(FutureTask.class.getDeclaredField("state"));
RUNNER = U.objectFieldOffset
(FutureTask.class.getDeclaredField("runner"));
WAITERS = U.objectFieldOffset
(FutureTask.class.getDeclaredField("waiters"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
// Reduce the risk of rare disastrous classloading in first call to
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
Class<?> ensureLoaded = LockSupport.class;
}
它對(duì)應(yīng)的就是runner的成員變量,也就是說如果狀態(tài)不是NEW或者runner不是null,run方法直接返回。
所以我們知道
- private static final long STATE:表示state這個(gè)成員變量
- private static final long RUNNER:表示的是runner這個(gè)成員變量
- rivate static final long WAITERS:表示的是waiters這個(gè)成員變量
在這個(gè)run方法里面分別調(diào)用了setException(Throwable )和set(V)方法,那我們就來詳細(xì)看下
1.2、setException(Throwable t)方法
/**
* Causes this future to report an {@link ExecutionException}
* with the given throwable as its cause, unless this future has
* already been set or has been cancelled.
*
* <p>This method is invoked internally by the {@link #run} method
* upon failure of the computation.
*
* @param t the cause of failure
*/
protected void setException(Throwable t) {
// state狀態(tài) NEW-> COMPLETING
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = t;
// // COMPLETING -> EXCEPTIONAL 到達(dá)穩(wěn)定狀態(tài)
U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
// 一些 結(jié)束工作
finishCompletion();
}
}
簡(jiǎn)單翻譯一下方法的注釋:
- 除非這個(gè)Future已經(jīng)設(shè)置過了,或者被取消了,否則這個(gè)產(chǎn)生的異常將會(huì)匯報(bào)到ExecutionException里面
- 如果在run()方法里面產(chǎn)生了異常,則會(huì)調(diào)用這個(gè)方法
所以總結(jié)一下就是:當(dāng)任務(wù)執(zhí)行過程中出現(xiàn)異常時(shí)候,對(duì)異常的處理方式
PS:這個(gè)方法是protected,所以可以重寫
1.3、set(V v)方法
這個(gè)方法主要是:執(zhí)行結(jié)果的賦值操作
/**
* Sets the result of this future to the given value unless
* this future has already been set or has been cancelled.
*
* <p>This method is invoked internally by the {@link #run} method
* upon successful completion of the computation.
*
* @param v the value
*/
protected void set(V v) {
// state 狀態(tài) NEW->COMPLETING
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
// COMPLETING -> NORMAL 到達(dá)穩(wěn)定狀態(tài)
U.putOrderedInt(this, STATE, NORMAL); // final state
// 一些結(jié)束工作
finishCompletion();
}
}
通過上面我們知道這個(gè)方法內(nèi)部的流程如下:
- 首先 將任務(wù)的狀態(tài)改變
- 其次 將結(jié)果賦值
- 再次 改變?nèi)蝿?wù)狀態(tài)
- 最后 處理等待線程隊(duì)列(將線程阻塞狀態(tài)改為喚醒,這樣等待線程就拿到結(jié)果了)
PS:這里使用的是 UNSAFE的putOrderedInt方法,其實(shí)就是原子量的LazySet內(nèi)部使用的方法,為什么要用這個(gè)方法?首先LazySet相對(duì)于Volatile-Write來說更加廉價(jià),因?yàn)樗鼪]有昂貴的Store/Load屏障,其次后續(xù)線程不會(huì)及時(shí)的看到state從COMPLETING變?yōu)镹ORMAL,但這沒有什么關(guān)系,而且NORMAL是state最終的狀態(tài),不會(huì)再變化了。
在這個(gè)方法里面調(diào)用了finishCompletion()方法,那我們就來看下這個(gè)方法
1.4、finishCompletion()方法
這個(gè)方法是:
在任務(wù)執(zhí)行完成(包括取消、正常結(jié)束、發(fā)生異常),將等待線程隊(duì)列喚醒,同時(shí)讓任務(wù)執(zhí)行體清空。
代碼如下:
/**
* Removes and signals all waiting threads, invokes done(), and
* nulls out callable.
*/
private void finishCompletion() {
// assert state > COMPLETING;
// 遍歷等待節(jié)點(diǎn)
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, 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;
}
}
// 這里可以自定義實(shí)現(xiàn)任務(wù)完成后要做的事情(在子類重寫done()方法)
done();
// 清空callable
callable = null; // to reduce footprint
}
由代碼和注釋可以看出來,這里就是遍歷WaitNode鏈表,對(duì)每一個(gè)WaitNode對(duì)應(yīng)的線程依次進(jìn)行LockSupport.unpark(t),使其結(jié)束阻塞。WaitNode通知完畢后,調(diào)用done方法。目前該方法是空實(shí)現(xiàn),所以如果你想在任務(wù)完成后執(zhí)行一些業(yè)務(wù)邏輯可以重寫這個(gè)方法。所以這個(gè)方法主要是在于喚醒等待線程。由前面知道,當(dāng)任務(wù)正常結(jié)束或者異常結(jié)束時(shí),都會(huì)調(diào)用finishCompletion()去喚醒等待線程。這時(shí)候等待線程就可以醒來,可以獲取結(jié)果了。
·
1.4.1、LockSupport簡(jiǎn)介
這里首先說下LockSupport,很多新手對(duì)這個(gè)東西,不是很熟悉,我先簡(jiǎn)單說下,這里就不詳細(xì)說明了。
LockSupport是構(gòu)建concurrent包的基礎(chǔ)之一
####### ① 操作對(duì)象
LockSupport調(diào)用Unsafe的natvie代碼:
public native void unpark(Thread jthread);
public native void park(boolean isAbsolute, long time);
這兩個(gè)函數(shù)聲明清楚地說明了操作對(duì)象:park函數(shù)是將當(dāng)前Thread阻塞,而unPark函數(shù)則是將另一個(gè)Thread喚醒。
與Object類的wait/notify 機(jī)制相比,park/unpark有兩個(gè)優(yōu)點(diǎn):
- 1、以thread為操作對(duì)象更符合阻塞線程的直觀定義
- 2、操作更精準(zhǔn),可以準(zhǔn)確地喚醒某一個(gè)線程(notify隨機(jī)喚醒一個(gè)線程,notifyAll喚醒所有等待的線程),增加了靈活性
####### ② 關(guān)于許可
在上面的文件,使用了阻塞和喚醒,是為了和wait/notify做對(duì)比。其實(shí)park/unpark的設(shè)計(jì)原理核心是"許可"。park是等待一個(gè)許可。unpark是為某線程提供一個(gè)"許可"。如果說某線程A調(diào)用park,那么除非另外一個(gè)線程unpark(A)給A一個(gè)許可,否則線程A將阻塞在park操作上。
1.5、handlePossibleCancellationInterrupt(int) 方法
/**
* Ensures that any interrupt from a possible cancel(true) is only
* delivered to a task while in run or runAndReset.
*/
private void handlePossibleCancellationInterrupt(int s) {
// It is possible for our interrupter to stall before getting a
// chance to interrupt us. Let's spin-wait patiently.
// 如果當(dāng)前正在中斷過程中,自等待,等中斷完成
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield(); // wait out pending interrupt
// assert state == INTERRUPTED;
// We want to clear any interrupt we may have received from
// cancel(true). However, it is permissible to use interrupts
// as an independent mechanism for a task to communicate with
// its caller, and there is no way to clear only the
// cancellation interrupt.
//
// Thread.interrupted();
}
先來看下注釋:
執(zhí)行計(jì)算而不設(shè)置其結(jié)果,然后重新設(shè)置future為初始化狀態(tài),如果執(zhí)行遇到異?;蛘呷蝿?wù)被取消,則不再執(zhí)行此操作。這樣設(shè)計(jì)的目的是:執(zhí)行多次任務(wù)。
看代碼我們知道他主要就是: 如果其他線程正在終止該任務(wù),那么運(yùn)行該任務(wù)的線程就暫時(shí)讓出CPU時(shí)間一直到state= INTERRUPTED為止。
所以它的作用就是:
確保cancel(true) 產(chǎn)生的中斷發(fā)生在run()或者 runAndReset()方法過程中
2、get()與get(long, TimeUnit)方法
任務(wù)是由線程池提供的線程執(zhí)行,那么這時(shí)候主線程則會(huì)阻塞,直到任務(wù)線程喚醒它們。我們看看get()是怎么做的?
2.1 get()方法
代碼如下:
/**
* @throws CancellationException {@inheritDoc}
*/
public V get() throws InterruptedException, ExecutionException {
int s = state;
// state 小于 COMPLETING 則說明任務(wù)仍然在執(zhí)行,且沒有被取消
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
通過代碼我們知道
- 首先 校驗(yàn)參數(shù)
- 然后 判斷是否正常執(zhí)行且沒有被取消,如果沒有則調(diào)用awaitDone(boolean,long)方法
- 最后 調(diào)用report(int) 方法
這里面涉及兩個(gè)方法分別是awaitDone(boolean,long)方法和report(int) 方法,那讓我們依次來看下。
2.1.1 awaitDone(boolean,long)方法
這個(gè)方法主要是等待任務(wù)執(zhí)行完畢,如果任務(wù)取消或者超時(shí)則停止
代碼如下:
/**
* Awaits completion or aborts on interrupt or timeout.
*
* @param timed true if use timed waits
* @param nanos time to wait, if timed
* @return state upon completion or at timeout
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
// The code below is very delicate, to achieve these goals:
// - call nanoTime exactly once for each call to park
// - if nanos <= 0L, return promptly without allocation or nanoTime
// - if nanos == Long.MIN_VALUE, don't underflow
// - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
// and we suffer a spurious wakeup, we will do no worse than
// to park-spin for a while
// 起始時(shí)間
long startTime = 0L; // Special value 0L means not yet parked
// 當(dāng)前等待線程的節(jié)點(diǎn)
WaitNode q = null;
// 是否將節(jié)點(diǎn)放在了等待列表中
boolean queued = false;
// 通過死循環(huán)來實(shí)現(xiàn)線程阻塞等待
for (;;) {
int s = state;
if (s > COMPLETING) {
// 任務(wù)可能已經(jīng)完成或者被取消了
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING)
// We may have already promised (via isDone) that we are done
// so never return empty-handed or throw InterruptedException
// 任務(wù)線程可能被阻塞了,讓出cpu
Thread.yield();
else if (Thread.interrupted()) {
// 線程中斷則移除等待線程并拋出異常
removeWaiter(q);
throw new InterruptedException();
}
else if (q == null) {
// 等待節(jié)點(diǎn)為空,則初始化新節(jié)點(diǎn)并關(guān)聯(lián)當(dāng)前線程
if (timed && nanos <= 0L)
// 如果需要等待,并且等待時(shí)間小于0表示立即,則直接返回
return s;
// 如果不需要等待,或者需要等待但是等待時(shí)間大于0。
q = new WaitNode();
}
else if (!queued)
// 等待線程入隊(duì),因?yàn)槿绻腙?duì)成功則queued=true
queued = U.compareAndSwapObject(this, WAITERS,
q.next = waiters, q);
else if (timed) {
//如果有超時(shí)設(shè)置
final long parkNanos;
if (startTime == 0L) { // first time
startTime = System.nanoTime();
if (startTime == 0L)
startTime = 1L;
parkNanos = nanos;
} else {
long elapsed = System.nanoTime() - startTime;
if (elapsed >= nanos) {
// 已經(jīng)超時(shí),則移除等待節(jié)點(diǎn)
removeWaiter(q);
return state;
}
parkNanos = nanos - elapsed;
}
// nanoTime may be slow; recheck before parking
if (state < COMPLETING)
// 任務(wù)還在執(zhí)行,且沒有被取消,所以繼續(xù)等待
LockSupport.parkNanos(this, parkNanos);
}
else
LockSupport.park(this);
}
}
兩個(gè)入?yún)ⅲ?/p>
- timed 為true 表示設(shè)置超時(shí)時(shí)間,false表示不設(shè)置超時(shí)間
- nanos 表示超時(shí)的狀態(tài)
for死循環(huán)里面的邏輯如下:
- 第一步 判斷任務(wù)是否已經(jīng)完處于完成或者取消了,如果直接返回轉(zhuǎn)狀態(tài)值,如果不是,則走第二步
- 第二步,如果狀態(tài)值是COMPLETING,則說明當(dāng)前是在set()方法時(shí)被阻塞了,所以只需要讓出當(dāng)前線程的CPU資源。
- 第三步,如果線程已經(jīng)中斷了,則移除線程并拋出異常
- 第四步,如果能走到這一步,狀態(tài)值只剩下NEW了,如果狀態(tài)值是NEW,并且q==null,則說明這是第一次,所以初始化一個(gè)當(dāng)前線程的等待節(jié)點(diǎn)。
- 第五步,此時(shí)queued=false,說明如果還沒入隊(duì),則它是在等待入隊(duì)
- 第六步,能走到這一步,說明queued=true,這時(shí)候判斷timed是否為true,如果為true則設(shè)置了超時(shí)時(shí)間,然后看一下startTime是否為0,如果為0,則說明是第一次,因?yàn)閟tartTime默認(rèn)值為0,如果是第一此,則設(shè)置startTime=1。保證startTime==0是第一次。如果startTime!=0,則說明不是第一次,如果不是第一次,則需要計(jì)算時(shí)差elapsed,如果elapsed大于nanos,則說明超時(shí),如果小于則沒有超時(shí),還有時(shí)差,然等待這個(gè)時(shí)差阻塞。
- 第七步,如果timed為false,則說明沒有超時(shí)設(shè)置。
所以總結(jié)一下:
waitDone就是將當(dāng)前線程加入等待隊(duì)列(waitNode有當(dāng)前Thread的Thread變量),然后用LockSupport將自己阻塞,等待超時(shí)或者被解除阻塞后,判斷是否已經(jīng)完成(state為>= COMPLETING),如果未完成(state< COMPLETING)拋出超時(shí)異常,如果已完成則稍等或者直接返回結(jié)果。
這個(gè)方法里面調(diào)用了removeWaiter(WaitNode) 這個(gè)方法,所以我們來先看這個(gè)這個(gè)removeWaiter(WaitNode) 里面是怎么實(shí)現(xiàn)的
2.1.2 removeWaiter(WaitNode)
/**
* Tries to unlink a timed-out or interrupted wait node to avoid
* accumulating garbage. Internal nodes are simply unspliced
* without CAS since it is harmless if they are traversed anyway
* by releasers. To avoid effects of unsplicing from already
* removed nodes, the list is retraversed in case of an apparent
* race. This is slow when there are a lot of nodes, but we don't
* expect lists to be long enough to outweigh higher-overhead
* schemes.
*/
private void removeWaiter(WaitNode node) {
if (node != null) {
// 將node 的thread 域置空
node.thread = null;
/**
* 下面過程中會(huì)將node從等待隊(duì)列中移除,以thread為null為依據(jù)
* 如果過程中發(fā)生了競(jìng)爭(zhēng),重試
*/
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 (!U.compareAndSwapObject(this, WAITERS, q, s))
continue retry;
}
break;
}
}
}
首先來看下類的注釋
為了防止累積的內(nèi)存垃圾,所以需要去取消超時(shí)或者已經(jīng)被中斷的等待節(jié)點(diǎn)。內(nèi)部節(jié)點(diǎn)因?yàn)闆]有CAS所以很簡(jiǎn)單,所以他們可以被無害的釋放。為了避免已刪除節(jié)點(diǎn)的影響,如果存在競(jìng)爭(zhēng)的情況下,需要重新排列。所以當(dāng)節(jié)點(diǎn)很多是,速度會(huì)很慢,因此我們不建議列表太長(zhǎng)而導(dǎo)致效率降低。
這個(gè)方法主要就是將線程節(jié)點(diǎn)從等待隊(duì)列中移除
2.1.2 report(int) 方法
/**
* Returns result or throws exception for completed task.
*
* @param s completed state value
*/
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
// 如果任務(wù)正常執(zhí)行完成,返回任務(wù)執(zhí)行結(jié)果
if (s == NORMAL)
return (V)x;
// 如果任務(wù)被取消,拋出異常
if (s >= CANCELLED)
throw new CancellationException();
// 其他狀態(tài) 拋出執(zhí)行異常 ExecutionException
throw new ExecutionException((Throwable)x);
}

如果任務(wù)處于NEW、COMPLETING和INTERRUPTING 這三種狀態(tài)的時(shí)候是執(zhí)行不到report方法的,所以沒有對(duì)這三種狀態(tài)盡心轉(zhuǎn)換。
2.2 get(long, TimeUnit)方法
最多等待為計(jì)算完成所給的時(shí)間之后,獲取其結(jié)果
/**
* @throws CancellationException {@inheritDoc}
*/
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
有參get方法源碼很簡(jiǎn)潔,首先校驗(yàn)參數(shù),然后根據(jù)state狀態(tài)判斷是否超時(shí),如果超時(shí)則異常,不超時(shí)則調(diào)用report去獲取最終結(jié)果。
當(dāng) s <= COMPLETING 時(shí),表明任務(wù)仍然在執(zhí)行且沒有被取消,如果它為true,那么走到awaitDone方法。關(guān)于awaitDone方法上面已經(jīng)講解了,這里就不過闡述了。
3、cancel(boolean)方法
只能取消還沒有被執(zhí)行的任務(wù)(任務(wù)狀態(tài)為NEW的任務(wù))
public boolean cancel(boolean mayInterruptIfRunning) {
// 如果任務(wù)狀態(tài)不是初始化狀態(tài),則取消任務(wù)
//如果此時(shí)任務(wù)已經(jīng)執(zhí)行了,并且可能執(zhí)行完成,但是狀態(tài)改變還沒有來得及修改,也就是在run()方法中的set()方法還沒來得及調(diào)用
// 繼續(xù)判斷任務(wù)的當(dāng)前狀態(tài)時(shí)否為NEW,因?yàn)榇藭r(shí)執(zhí)行任務(wù)線程可能再度獲得處理了,任務(wù)狀態(tài)可能已發(fā)生改變
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
// 如果任務(wù)狀態(tài)依然是NEW,也就是執(zhí)行線程沒有改變?nèi)蝿?wù)的狀態(tài),
// 則讓執(zhí)行線程中斷(在這個(gè)過程中執(zhí)行線程可能會(huì)改變?nèi)蝿?wù)的狀態(tài))
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
// 將任務(wù)狀態(tài)設(shè)置為中斷
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
// 處理任務(wù)完成的結(jié)果
finishCompletion();
}
return true;
}
通過上述代碼,我們知道這個(gè)取消不一定起作用的。
上面的代碼邏輯如下:
- 第一步:state不等于NEW,則表示任務(wù)即將進(jìn)入最終狀態(tài) ,則state == NEW為false,導(dǎo)致if成立直接返回false
- 第二步:如果mayInterruptIfRunning為true在,表示中斷線程,則設(shè)置狀態(tài)為INTERRUPTING,中斷之后設(shè)置為INTERRUPTED。如果mayInterruptIfRunning為false,表示不中斷線程,把state設(shè)置為CANCELLED
- 第三步:state狀態(tài)為NEW,任務(wù)可能已經(jīng)開始執(zhí)行,也可能還未開始,所以用Unsafe查看下,如果不是,則直接返回false
- 第四步:移除等待線程
- 第五步:?jiǎn)拘?/li>
所以,cancel()方法改變了futureTask的狀態(tài)為,如果傳入的是false,并且業(yè)務(wù)邏輯已經(jīng)開始執(zhí)行,當(dāng)前任務(wù)是不會(huì)被終止的,而是會(huì)繼續(xù)執(zhí)行,知道異?;蛘邎?zhí)行完畢。如果傳入的是true,會(huì)調(diào)用當(dāng)前線程的interrupt()方法,把中斷標(biāo)志位設(shè)為true。
事實(shí)上,除非線程自己停止自己的任務(wù),或者退出JVM,是沒有其他方法完全終止一個(gè)線程任務(wù)的。mayInterruptIfRunning=true,通過希望當(dāng)前線程可以響應(yīng)中斷的方式來結(jié)束任務(wù)。當(dāng)任務(wù)被取消后,會(huì)被封裝為CancellationException拋出。
4、runAndReset() 方法
任務(wù)可以被多次執(zhí)行
/**
* Executes the computation without setting its result, and then
* resets this future to initial state, failing to do so if the
* computation encounters an exception or is cancelled. This is
* designed for use with tasks that intrinsically execute more
* than once.
*
* @return {@code true} if successfully run and reset
*/
protected boolean runAndReset() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable<V> c = callable;
if (c != null && s == NEW) {
try {
c.call(); // don't set result
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} 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
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
}
先來看下注釋:
執(zhí)行計(jì)算而不設(shè)置其結(jié)果,然后重新設(shè)置future為初始化狀態(tài),如果執(zhí)行遇到異常或者任務(wù)被取消,則不再執(zhí)行此操作。這樣設(shè)計(jì)的目的是:執(zhí)行多次任務(wù)。
我們可以對(duì)比一下runAndReset與run方法,其實(shí)兩者相差不大,主要就是有兩點(diǎn)區(qū)別
- 1 run()方法里面設(shè)置了result的值,而runAndReset()則移除了這段代碼
下面我們就來看下handlePossibleCancellationInterrupt(int) 這個(gè)方法
五、總結(jié)
FutureTask大部分就簡(jiǎn)單分析完了,其他的自己看下就行了。FutureTask中的任務(wù)狀態(tài)由變量state表示,任務(wù)狀態(tài)都是基于state判斷。而FutureTask的阻塞則是通過自旋+掛起線程實(shí)現(xiàn)的。