ThreadPoolExecutor中的submit()方法詳細(xì)講解
在使用線程池的時(shí)候,發(fā)現(xiàn)除了execute()方法可以執(zhí)行任務(wù)外,還發(fā)現(xiàn)有一個(gè)方法submit()可以執(zhí)行任務(wù)。
submit()有3個(gè)參數(shù)不一的方法,這些方法都是在ExecutorService接口中聲明的,在AbstractExecutorService中實(shí)現(xiàn),而ThreadPoolExecutor繼承AbstractExecutorService。
<T> Future<T> submit(Callable<T> callable); <T> Future<T> submit(Runnable var1, T result); Future<?> submit(Runnable runnable);
我們可以看到submit()的參數(shù)既可以是Runnable,又可以是Callable。對(duì)于Runnable我們是比較熟的,它是線程Thread所執(zhí)行的任務(wù),里面有一個(gè)run()方法,是任務(wù)的具體執(zhí)行操作。那么Callable呢?我們一起看下他們的代碼吧。
public interface Runnable { ? ? void run(); } public interface Callable<V> { ? ? V call() throws Exception; }
Runnable這里就不介紹了,Callable接口定義了一個(gè)call()方法,返回一個(gè)Callable指定的泛型類,并且call()調(diào)用的時(shí)候會(huì)拋出異常。通過(guò)比較Runnable和Callable還看不什么端倪,那么我們就看看內(nèi)部實(shí)現(xiàn)吧。
submmit()參數(shù)解析
這里重點(diǎn)分析submit()帶參數(shù)Runnable和Callable的方法
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(Callable<T> task) { ? ? if (task == null) throw new NullPointerException(); ? ? RunnableFuture<T> ftask = newTaskFor(task); ? ? execute(ftask); ? ? return ftask; }
我們發(fā)現(xiàn)2者的實(shí)現(xiàn)沒(méi)有任何的差異,唯一就是submit()參數(shù)不同。
參數(shù)傳入newTaskFor()方法,那么可以肯定就是在這個(gè)方法里做了什么操作。
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); }
newTaskFor()的目的就是創(chuàng)建一個(gè)FutureTask對(duì)象,那我們追蹤到FutureTask的構(gòu)造方法(FutureTask非常關(guān)鍵,后面會(huì)分析)。
public FutureTask(Runnable runnable, V result) { ? ? this.callable = Executors.callable(runnable, result); ? ? this.state = NEW; ? ? ?? } public FutureTask(Callable<V> callable) { ? ? if (callable == null)throw new NullPointerException(); ? ? this.callable = callable; ? ? this.state = NEW; ? ? ?? }
到了這里我們知道,其實(shí)Runnable會(huì)在這里轉(zhuǎn)化成Callable。我們來(lái)看下Executors.callable()具體實(shí)現(xiàn)。
public static <T> Callable<T> callable(Runnable task, T result) { ? ? if (task == null) ? ? ? ? throw new NullPointerException(); ? ? return new RunnableAdapter<T>(task, 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; ? ? } }
Executors.callable()創(chuàng)建了一個(gè)RunnableAdapter對(duì)象,RunnableAdapter實(shí)現(xiàn)了Callable接口,在call()方法中調(diào)用了傳入的Runnable的run(),并且將傳入的result參數(shù)返回。
也就是說(shuō)我們調(diào)用submit()傳入的Runnbale最終會(huì)轉(zhuǎn)化成Callable,并且返回一個(gè)result值(如果我們傳入這個(gè)參數(shù)則返回這個(gè)參數(shù),不傳入則返回null)。
到這里我們講清楚了submit()的參數(shù)的區(qū)別和內(nèi)部實(shí)現(xiàn),submit()方法有一個(gè)返回值Future,下面我們來(lái)分析一下返回值Future。
submit()的返回值Future
上面分析submit()源碼可知,submit()返回的是一個(gè)RunnableFuture類對(duì)象,真正是通過(guò)newTaskFor()方法返回一個(gè)new FutureTask()對(duì)象。所以submit()返回的真正的對(duì)象是FutureTask對(duì)象。
那么FutureTask是什么,我們來(lái)看下它的類繼承關(guān)系。
public class FutureTask<V> implements RunnableFuture<V> { ? ? ... } public interface RunnableFuture<V> extends Runnable, Future<V> { ? ? void run(); }
通過(guò)繼承關(guān)系我們可以明確的知道其實(shí)FutureTask就是一個(gè)Runnable。并且有自己run()實(shí)現(xiàn)。我們來(lái)看下FutureTask的run()是如何實(shí)現(xiàn)的。
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, 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 { // 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); } }
我們?cè)趎ew FutureTask()對(duì)象的時(shí)候,在FutureTask構(gòu)造方法中會(huì)對(duì)state狀態(tài)賦值為NEW,并且傳入一個(gè)callable對(duì)象。通過(guò)FutureTask的run()我們可以知道,其實(shí)就通過(guò)state狀態(tài)判斷,調(diào)用callable的call()。(如果傳入的參數(shù)是Runnable,Runnable在RunnableAdapter類中轉(zhuǎn)化時(shí),在call()中,其實(shí)調(diào)用的就是Runnable的run()方法)。
所以在submit()方法中,調(diào)用了一個(gè)execute(task)的方法,實(shí)際執(zhí)行的是FutureTask的run(),而FutureTask的run()調(diào)用的是Callable的call()方法。
說(shuō)了這么多,submit()最后執(zhí)行的還是傳入的Runnable的run()或Callable的call()方法。好像沒(méi)有FutureTask什么事啊。
其實(shí)不是,submit()返回FutureTask對(duì)象,通過(guò)這個(gè)FutureTask對(duì)象調(diào)用get()可以返回submit()方法傳入的一個(gè)泛型類參數(shù)result對(duì)象,如果是Callable直接通過(guò)call()返回。這個(gè)返回值的可以用來(lái)校驗(yàn)任務(wù)執(zhí)行是否成功。
FutureTask的get()的實(shí)現(xiàn)
public V get() throws InterruptedException, ExecutionException { ? ? int s = state; ? ? if (s <= COMPLETING) ? ? ? ? s = awaitDone(false, 0L); ? //等待任務(wù)執(zhí)行完 ? ? return report(s);//將執(zhí)行的任務(wù)結(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); }
最后是通過(guò)outcome參數(shù)將根據(jù)任務(wù)的狀態(tài)將結(jié)果返回。那么outcome參數(shù)在哪里賦值了?outcome參數(shù)賦值的地方有好2處,一是FutureTask的set(),二是FutureTask的setException()。
set()是在FutureTask的run()執(zhí)行完成后,將傳入的result參數(shù)賦值給傳入給set(),賦值給outcome參數(shù)。如果run()報(bào)異常了會(huì)將Throwable對(duì)象通過(guò)setException()方法傳入,賦值給outcome變量
大家可以返回上面的run()查看下。
protected void set(V v) { ? ? if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) { ? ? ? ? outcome = v; ? ? ? ? U.putOrderedInt(this, STATE, NORMAL); // final state ? ? ? ? finishCompletion(); ? ? } } protected void setException(Throwable t) { ? ? if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) { ? ? ? ? outcome = t; ? ? ? ? U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state ? ? ? ? finishCompletion(); ? ? } }
submit()使用案例
public class Test { ? ? private static final String SUCCESS = "success"; ? ? public static void main(String[] args) { ? ? ? ? ExecutorService executorService = Executors.newFixedThreadPool(3); ? ? ? ? System.out.println("------------------任務(wù)開(kāi)始執(zhí)行---------------------"); ? ? ? ? Future<String> future = executorService.submit(new Callable<String>() { ? ? ? ? ? ? @Override ? ? ? ? ? ? public String call() throws Exception { ? ? ? ? ? ? ? ? Thread.sleep(5000); ? ? ? ? ? ? ? ? System.out.println("submit方法執(zhí)行任務(wù)完成" + " ? thread name: " + Thread.currentThread().getName()); ? ? ? ? ? ? ? ? return SUCCESS; ? ? ? ? ? ? } ? ? ? ? }); ? ? ? ? try { ? ? ? ? ? ? String s = future.get(); ? ? ? ? ? ? if (SUCCESS.equals(s)) { ? ? ? ? ? ? ? ? String name = Thread.currentThread().getName(); ? ? ? ? ? ? ? ? System.out.println("經(jīng)過(guò)返回值比較,submit方法執(zhí)行任務(wù)成功 ? ?thread name: " + name); ? ? ? ? ? ? } ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } catch (ExecutionException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? System.out.println("-------------------main thread end---------------------"); ? ? } }
打印結(jié)果:
------------------任務(wù)開(kāi)始執(zhí)行---------------------
call()調(diào)用開(kāi)始: 1496899867882
submit方法執(zhí)行任務(wù)完成: 1496899872897 thread name: pool-1-thread-1
經(jīng)過(guò)返回值比較,submit方法執(zhí)行任務(wù)成功 thread name: main
-------------------main thread end---------------------
主線程會(huì)一直阻塞,等待線程池中的任務(wù)執(zhí)行完后,在執(zhí)行后面的語(yǔ)句。
到此這篇關(guān)于ThreadPoolExecutor中的submit()方法詳細(xì)講解的文章就介紹到這了,更多相關(guān)ThreadPoolExecutor submit()方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 實(shí)戰(zhàn)范例之精美網(wǎng)上音樂(lè)平臺(tái)的實(shí)現(xiàn)
讀萬(wàn)卷書(shū)不如行萬(wàn)里路,只學(xué)書(shū)上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+vue+Springboot+ssm+mysql+maven+redis實(shí)現(xiàn)一個(gè)前后端分離的精美網(wǎng)上音樂(lè)平臺(tái),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2021-11-11springboot2.0整合logback日志的詳細(xì)代碼
這篇文章主要介紹了springboot2.0整合logback日志的應(yīng)用場(chǎng)景分析,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02SpringBoot集成tomcat詳解實(shí)現(xiàn)過(guò)程
采用spring boot之后,一切變得如此簡(jiǎn)單,打包->java-jar->運(yùn)維,只需要一個(gè)jar包便可以隨意部署安裝。這篇文章,將對(duì) spring boot集成tomcat的源碼進(jìn)行分析,探索其內(nèi)部的原理2023-02-02使用Spring CROS解決項(xiàng)目中的跨域問(wèn)題詳解
這篇文章主要介紹了使用Spring CROS解決項(xiàng)目中的跨域問(wèn)題詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01MyBatis測(cè)試報(bào)錯(cuò):Cannot?determine?value?type?from?string?&a
這篇文章主要給大家介紹了關(guān)于MyBatis測(cè)試報(bào)錯(cuò):Cannot?determine?value?type?from?string?'xxx'的解決辦法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02SpringBoot實(shí)現(xiàn)發(fā)送郵件任務(wù)
這篇文章主要為大家詳細(xì)介紹了SpringBoot實(shí)現(xiàn)發(fā)送郵件任務(wù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02