1. 程式人生 > >java:執行緒池任務提交(Runnable、Callable、FutureTask)

java:執行緒池任務提交(Runnable、Callable、FutureTask)

任務的封裝與執行過程

(注:下面所說的Runnable物件,Callable物件都是指實現了該介面的類的物件)

之前要交給執行緒執行的任務我們都把它封裝在Runnable中。對於執行緒池而言,多了一種Callable的封裝方式。

Runnable:其中的run()方法沒有返回值。

①.Runnable物件可以直接扔給Thread建立執行緒例項,並且建立的執行緒例項與Runnable繫結,執行緒例項呼叫start()方法時,Runnable任務就開始真正線上程中執行。注意:如果直接呼叫run()方法而不呼叫start()方法,那麼只是相當於普通的方法呼叫,並不會開啟新的執行緒,程式只是在主執行緒中序列執行。

②.Runnable物件也可以直接扔給執行緒池物件的execute方法和submit方法,讓執行緒池為其繫結池中的執行緒來執行。

③.Runnable物件也可以進一步封裝成FutureTask物件之後再扔給執行緒池的execute方法和submit方法。

Callable:功能相比Runnable來說少很多,不能用來建立執行緒,也不能直接扔給執行緒池的execute方法。但是其中的call方法有返回值。

FutureTask:是對Runnable和Callable的進一步封裝,並且這種任務是有返回值的,它的返回值存在FutureTask類的一個名叫outcome的資料成員中。(疑惑)那麼為什麼可以把沒有返回值的Runnable也封裝成FutureTask呢,馬上我們會討論這個問題。相比直接把Runnable和Callable扔給執行緒池,FutureTask的功能更多,它可以監視任務在池子中的狀態。用Runnable和Callable建立FutureTask的方法稍有不同。

①.使用Callable來建立,由於call方法本身有返回值,這個返回值也就是Callable物件的返回值,於是可以把這個返回值當做FutureTask的返回值,也就是拿call方法的返回值去初始化outcome欄位(是Object的引用,可以理解成引用的Future物件),這個真正初始化過程要在submit方法把任務扔給池子之後並且該任務在池子中分配到了執行緒並且線上程中執行完了產生了結果之後。但是在這一系列動作之前會有一個偽初始化,submit方法一旦提交任務到執行緒池馬上會得到一個返回值(Future物件,用來指代剛才提交的任務的結果,相當於付錢買了商品但是沒貨了,暫時拿了一個票據,到了貨再真的的取貨,這個Future物件就相當於票據),submit方法不會真正等到上面的那一系列動作執行完才返回,所以需要使用這個任務執行結果的那些執行緒就可以拿著這個返回值(Future物件)去該怎麼用就怎麼用了。(之所以叫偽初始化,因為call方法也許還沒有開始執行,任務還線上程池的任務佇列中排隊呢。)所以在建立FutureTask的時候只用給FutureTask的構造方法傳一個Callable物件既可。原始碼中方法簽名如下:

②.使用Runnable來建立(我們通常不這麼幹),正如上面所疑惑的那樣,run方法沒有返回值,也就是Runnable任務沒有返回值,那麼為什麼用它封裝的FutureTask卻有了返回值了呢。原因在於這種方法建立的FutureTask物件並不是把run的返回值當成自己的返回值,而是在建立FutureTask物件時就已經手動指定了這個FutureTask物件的返回值了。若不希望FutureTask物件有真正意義上的返回值,我們可以在呼叫用FutureTask的構造方法時指定第二個引數為null,對應構造方法使用FutureTask<Void>。原始碼中方法簽名如下:

原文參考:https://blog.csdn.net/qq_26963495/article/details/79015110