結(jié)論
今天先說結(jié)論吧:
- execute:1.只能提交Runnable接口的對(duì)象,我們知道Runnable接口的run方法是沒有返回值的。2.execute方法提交的任務(wù)異常是直接拋出的
- submit: 1.可以提交Runnable也可以提交Callable對(duì)象穷蛹,即可以有返回值,也可以沒有践美。2.submit方法是是捕獲了異常的朗兵,當(dāng)調(diào)用FutureTask的get方法時(shí),才會(huì)拋出異常柿隙。
例子還是在github中
先對(duì)比api
//只接受Runnable對(duì)象沒有返回值
public void execute(Runnable command)
//接受Runnable對(duì)象并返回Future對(duì)象叶洞,調(diào)用Future的get時(shí),正常完成后禀崖,返回null
public Future<?> submit(Runnable task)
//接受Runnable對(duì)象并返回Future對(duì)象衩辟,調(diào)用Future的get時(shí),正常完成后,返回指定的result對(duì)象
public <T> Future<T> submit(Runnable task, T result)
//接受Callable對(duì)象并返回Future對(duì)象波附,調(diào)用Future的get時(shí),正常完成后艺晴,返回task的結(jié)果
public <T> Future<T> submit(Callable<T> task)
execute方法上篇文章已經(jīng)分析過了,這篇我們主要看下submit方法的實(shí)現(xiàn)掸屡,submit三個(gè)方法實(shí)現(xiàn)類似封寞,我們用其中一個(gè)舉例。
public Future<?> submit(Runnable task) {
//task對(duì)象不能為空
if (task == null) throw new NullPointerException();
//將task構(gòu)造成一個(gè)RunnableFuture對(duì)象
RunnableFuture<Void> ftask = newTaskFor(task, null);
//調(diào)用execute方法執(zhí)行RunnableFuture對(duì)象
execute(ftask);
//返回future對(duì)象
return ftask;
}
可以看到仅财,submit復(fù)用了execute方法狈究,submit僅僅將傳入的Runnable或者Callable構(gòu)造成一個(gè)RunnableFuture,我們一起看看newTaskFor方法
//構(gòu)造FutureTask返回
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
可以看到主要的不同盏求,就是這個(gè)FutureTask抖锥,我們看看FutureTask吧。
public class FutureTask<V> implements RunnableFuture<V> {
}
public interface RunnableFuture<V> extends Runnable, Future<V>
通過上面可以看到FutureTask是實(shí)現(xiàn)了Runnable和Future兩個(gè)接口碎罚,我們知道Future接口提供了cancel磅废,isCancelled,isDone荆烈,get方法还蹲,用于獲取子線程執(zhí)行的結(jié)果。
FutureTask類結(jié)構(gòu)
public class FutureTask<V> implements RunnableFuture<V> {
/**
* 可能出現(xiàn)的狀態(tài)路徑
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
//任務(wù)執(zhí)行的狀態(tài)
private volatile int state;
private static final int NEW = 0; //初始化狀態(tài)
private static final int COMPLETING = 1; //任務(wù)正常結(jié)束或者拋出異常時(shí)的中間態(tài) 這是一個(gè)過渡狀態(tài)
private static final int NORMAL = 2; //任務(wù)正常結(jié)束
private static final int EXCEPTIONAL = 3; //任務(wù)異常結(jié)束
private static final int CANCELLED = 4; //任務(wù)被取消耙考, 注意任務(wù)只有在new狀態(tài)的時(shí)候谜喊,才可以被取消
private static final int INTERRUPTING = 5; //任務(wù)到中斷狀態(tài)的中間態(tài)
private static final int INTERRUPTED = 6; //任務(wù)被中斷
//執(zhí)行任務(wù)的callable對(duì)象,可以看到傳入的runnable也會(huì)被構(gòu)造成callable
private Callable<V> callable;
//正常返回時(shí)的結(jié)果或者任務(wù)拋出的異常
private Object outcome; // non-volatile, protected by state reads/writes
//運(yùn)行callable的線程
private volatile Thread runner;
//等待的線程節(jié)點(diǎn)倦始,調(diào)用get方法時(shí)斗遏,如果線程沒有運(yùn)行結(jié)束,需要進(jìn)入等待隊(duì)列進(jìn)行等待
private volatile WaitNode waiters;
鞋邑。诵次。账蓉。
}
我們上面看到ThreadPoolExecutor調(diào)用的是傳入Runnable的構(gòu)造方法。
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
可以看到構(gòu)造方法中將傳入的Runnable對(duì)象逾一,適配成了RunnableAdapter對(duì)象铸本,另外將state設(shè)置成NEW的狀態(tài)。
通過上篇的分析遵堵,我們知道execute最終執(zhí)行的是Runnable的run方法箱玷,在這里即FutureTask的run方法。
public void run() {
//狀態(tài)不為初始狀態(tài)或者CAS替換runner為本線程失敗陌宿,都直接返回锡足,說明任務(wù)被別人處理了
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
//將runner設(shè)置為自己后,任務(wù)被自己搶到了
//任務(wù)不為空且是初始狀態(tài)
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//調(diào)用Callable對(duì)象的call方法
result = c.call();
//正常執(zhí)行完成
ran = true;
} catch (Throwable ex) {
//Callable對(duì)象的call方法拋出了異常
result = null;
ran = false;
//將異常對(duì)象放到outcome屬性中壳坪,標(biāo)記任務(wù)為異常狀態(tài)舶得,喚醒等待的線程
//這里可以看到對(duì)異常進(jìn)行了捕獲,也就是文章開頭的結(jié)論2
setException(ex);
}
//如果Callable對(duì)象的call方法正常執(zhí)行完成
//將正常結(jié)果放到outcome屬性中爽蝴,標(biāo)記任務(wù)為正常完成的狀態(tài)沐批,喚醒等待的線程
if (ran)
set(result);
}
} finally {
runner = null;
// 再次處理INTERRUPTING狀態(tài)
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
setException 和set方法是兩種不同情況的結(jié)束,但代碼類似蝎亚,我們看看正常結(jié)束的set方法
protected void set(V v) {
//標(biāo)記state為COMPLETING狀態(tài)
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//將正常結(jié)果賦值給outcome
outcome = v;
//標(biāo)記狀態(tài)為NORMAL(正常結(jié)束)
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
//喚醒等待線程
finishCompletion();
}
}
finishCompletion方法
private void finishCompletion() {
// assert state > COMPLETING;
//循環(huán)喚起全部的等待線程珠插,后面會(huì)看到其他線程調(diào)用get方法,如果任務(wù)還沒完成會(huì)進(jìn)入等待隊(duì)列
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;
}
}
done();
callable = null; // to reduce footprint
}
前面我們看到set方法或者setException最后都會(huì)進(jìn)行喚醒掛起的線程颖对,現(xiàn)在就一起看看get方法
public V get() throws InterruptedException, ExecutionException {
int s = state;
//如果任務(wù)的狀態(tài)為未完成的狀態(tài)捻撑,進(jìn)行等待
//注意:這里的等待線程和執(zhí)行任務(wù)的線程不是同一個(gè)哦,可以想象主線程new 線程池執(zhí)行任務(wù)缤底,一般都是在主線程中獲取任務(wù)的結(jié)果顾患,就是調(diào)用的get方法
if (s <= COMPLETING)
s = awaitDone(false, 0L);
//任務(wù)完成以后,根據(jù)任務(wù)的狀態(tài)个唧,返回正常的執(zhí)行結(jié)果江解,或者
return report(s);
}
awaitDone方法
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
//響應(yīng)中斷的等待
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
//如果任務(wù)已經(jīng)完成直接返回
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
// 任務(wù)在中間態(tài),說明應(yīng)該很快就能出結(jié)果徙歼,做一個(gè)讓步犁河,就不在掛起了
else if (s == COMPLETING)
Thread.yield();
else if (q == null) //構(gòu)造一個(gè)等待節(jié)點(diǎn)
q = new WaitNode();
else if (!queued)
//將等待節(jié)點(diǎn)入隊(duì)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
//如果是超時(shí)等待,判斷是否已經(jīng)超時(shí)魄梯,超時(shí)了直接返回
//沒超時(shí)桨螺,進(jìn)行剩余時(shí)間的掛起(有超時(shí)時(shí)間的掛起是可以自喚醒的)
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
//掛起自己, 這里就和finishCompletion方法里的LockSupport.unpark對(duì)上了
LockSupport.park(this);
//注意:外層無限循環(huán)的操作酿秸,所以串起來就是構(gòu)造一個(gè)等待節(jié)點(diǎn)灭翔,再次進(jìn)入for循環(huán),將節(jié)點(diǎn)進(jìn)入等待隊(duì)列辣苏,再次進(jìn)入for循環(huán)掛起自己肝箱。
//當(dāng)被喚醒后哄褒,再次進(jìn)入for循環(huán),判斷state> COMPLETING, 方法返回
}
}