深夜學(xué)習(xí),,發(fā)現(xiàn)ThreadPoolExecutor里面一個(gè)小知識(shí)點(diǎn),,故開(kāi)熱點(diǎn)連wifi怒寫(xiě)submit與execute方法的區(qū)別,。
1.問(wèn)題的來(lái)源
在看書(shū)的時(shí)候,涉及到j(luò)ava線程池問(wèn)題的時(shí)候常常面臨這樣一個(gè)問(wèn)題,。當(dāng)定義了一個(gè)Runnable對(duì)象想提交到線程池里面總是會(huì)看到不同的提交方法,,產(chǎn)生的尬題如下:
public class ThreadPoolDemo {
public static class MyTask implements Runnable{
@Override
public void run() {
System.out.println(System.currentTimeMillis()+":Thread ID:"+Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
MyTask task = new MyTask();
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<10;i++){
es.submit(task);//問(wèn)題出現(xiàn)在這里!
es.execute(task);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
明明在看上一頁(yè)書(shū)的時(shí)候,,向線程池提交任務(wù)的時(shí)候,,用的是submit()方法,等到看下一頁(yè)的時(shí)候媽蛋,怎么用成execute()了,,這兩個(gè)搞什么鬼,,同一個(gè)功能難道有兩個(gè)方法可以調(diào)用?我不精陷入了深思,,怒查java api文檔。
2.java api文檔對(duì)這兩個(gè)方法的描述
首先,,記憶里面對(duì)execute()方法是記憶比較深刻的,,故查了一下該方法的api文檔,發(fā)現(xiàn)信息如下:
- execute() 是在Executor接口中定義的,,ThreadPoolExecutor繼承了AbstractExecutorService抽象類(lèi),,該抽象類(lèi)實(shí)現(xiàn)了ExecutorService接口(但并沒(méi)有覆蓋execute方法),而ExecutorService接口繼承了Executor接口,。
簡(jiǎn)而言之就是說(shuō)ThreadPoolExecutor實(shí)現(xiàn)了execute()方法,。然后我們來(lái)看看api文檔對(duì)execute()方法是如何定義的:
execute public void execute(Runnable command)
在將來(lái)某個(gè)時(shí)間執(zhí)行給定任務(wù)??梢栽谛戮€程中或者在現(xiàn)有池線程中執(zhí)行該任務(wù),。如果無(wú)法將任務(wù)提交執(zhí)行,或者因?yàn)榇藞?zhí)行程序已關(guān)閉,,或者因?yàn)橐堰_(dá)到其容量,,則該任務(wù)由當(dāng)前 RejectedExecutionHandler處理。
參數(shù): command - 要執(zhí)行的任務(wù),。 拋出: RejectedExecutionException -
如果無(wú)法接收要執(zhí)行的任務(wù),,則由 RejectedExecutionHandler 決定是否拋出
RejectedExecutionException NullPointerException - 如果命令為 null
看的是我一蒙一蒙的,主要是”在將來(lái)某個(gè)時(shí)間執(zhí)行給定任務(wù),?!边@一句讓我很費(fèi)解,所以我決定再看看submit()方法是怎么寫(xiě)的,。
- submit方法是ExecutorService接口里面定義的,,具體的實(shí)現(xiàn)由AbstractExecutorService進(jìn)行。
submit方法被重載了三次,,分別對(duì)用三個(gè)不同的參數(shù),。對(duì)api摘錄如下:
submit public Future<?> submit(Runnable task)
提交一個(gè) Runnable 任務(wù)用于執(zhí)行,,并返回一個(gè)表示該任務(wù)的 Future,。該 Future 的 get 方法在成功 完成時(shí)將會(huì)返回null。
指定者: 接口 ExecutorService 中的 submit 參數(shù): task - 要提交的任務(wù) 返回: 表示任務(wù)等待完成的 Future
submit public Future submit(Runnable task,T result) 提交一個(gè)
Runnable 任務(wù)用于執(zhí)行,,并返回一個(gè)表示該任務(wù)的 Future,。該 Future 的 get 方法在成功完成時(shí)將會(huì)返回給定的結(jié)果。
指定者: 接口 ExecutorService 中的 submit 參數(shù): task - 要提交的任務(wù) result - 返回的結(jié)果
返回: 表示任務(wù)等待完成的 Future
submit public Future submit(Callable task)
提交一個(gè)返回值的任務(wù)用于執(zhí)行,返回一個(gè)表示任務(wù)的未決結(jié)果的 Future,。該 Future 的 get
方法在成功完成時(shí)將會(huì)返回該任務(wù)的結(jié)果,。 如果想立即阻塞任務(wù)的等待,則可以使用 result =
exec.submit(aCallable).get(); 形式的構(gòu)造,。
注:Executors 類(lèi)包括了一組方法,,可以轉(zhuǎn)換某些其他常見(jiàn)的類(lèi)似于閉包的對(duì)象,例如,,將 PrivilegedAction 轉(zhuǎn)換為Callable 形式,,這樣就可以提交它們了。
指定者: 接口 ExecutorService 中的 submit 參數(shù): task - 要提交的任務(wù) 返回: 表示任務(wù)等待完成的Future
如上所示,,第二個(gè)與第三個(gè)可以理解,,不就是我記錄過(guò)的Future模式里面的那一套東西嗎?就是說(shuō)execute不支持Future這一套,,而submit支持一套并可以返回一個(gè)Future給你到后面獲取結(jié)果的時(shí)候可以get一get,。
但是看到第一個(gè)的時(shí)候我又蒙蔽了,”提交一個(gè) Runnable 任務(wù)用于執(zhí)行,,并返回一個(gè)表示該任務(wù)的 Future,。該 Future 的 get 方法在成功 完成時(shí)將會(huì)返回null?!眿尩?,那這樣與execute又有什么區(qū)別呀。何必這樣多此一舉呢,?我不服,,我認(rèn)為execute與submit里面肯定存在互相調(diào)用的關(guān)系,畢竟ExecutorService是Executor的子類(lèi)嘛
3.怒開(kāi)IDE,,深入源碼一探究竟
寫(xiě)了一個(gè)線程池,,ctrl+左鍵深入execute方法,發(fā)現(xiàn)代碼如下:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
這不是關(guān)于任務(wù)到線程池里面一些具體的操作嗎!菜鳥(niǎo)太菜有些方法還是深入理解不了,,不談,。回到剛剛想的那個(gè)問(wèn)題,,這樣的話那么execute方法就是具體對(duì)任務(wù)的操作,,那么submit方法呢?
點(diǎn)擊進(jìn)入了AbstractExecutorService抽象類(lèi)源代碼,,發(fā)現(xiàn)源碼如下:
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
這媽蛋,,不是都把拿到的Runnable任務(wù)都構(gòu)造了RunnableFuture任務(wù)然后都拋給execute方法嗎!也是醉了,,
得出結(jié)論1:如果提交的任務(wù)不需要一個(gè)結(jié)果的話直接用execute()會(huì)提升很多性能,。
那我奇怪了newTaskFor這個(gè)又是什么jb玩意啊,,用這個(gè)函數(shù)是怎么構(gòu)造一個(gè)RunnableFuture任務(wù)的,怒氣又來(lái)進(jìn)入了方法,,得結(jié)果如下:
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
罵了個(gè)比啊,,這個(gè)方法不是幫你new了FutureTask嗎!氣得我得出
結(jié)論二:就是相當(dāng)于說(shuō)如果你傳的任務(wù)是需要結(jié)果的,,那你就使用你的類(lèi)去繼承Callable接口,,然后告訴submit方法就行了,如果你只需要一個(gè)特定的結(jié)果,,就把那個(gè)特定的結(jié)果告訴submit方法然后把你想要的特定結(jié)果也告訴他,,它只是幫你完成以前使用Future模式的時(shí)候你自己需要做的那些步驟而已,如果你不需要一個(gè)結(jié)果,,那么就老老實(shí)實(shí)使用execute,,如果你需要的是一個(gè)空結(jié)果,,那么submit(yourRunnable)與submit(yourRunnable,null)是等價(jià)的,!
|