在使用執行緒池的時候,我們需要使用到callable介面,那我們來看一下calllable的底層是怎麼實現,並且有返回值的。
首先我們看一下呼叫。
threadpoolexcutor並沒有實現
submit
方法,那麼肯定是它的父類實現的。
如願以償在abstractexecutorservice中找到了
submit
方法,找到對應的方法,根據我們傳入的
callable
介面找到。
在上面我們可以看到我們將callable或者
runnable
傳入進去給我們返回了乙個
runnablefuture,
實際上是返回了乙個它的實現futuretask,這就是核心類。
這裡實際上做的是callable賦值,第乙個構造就是直接賦值給
callable
就行,但是第二個構造方法是傳入的
runnable
,並不能直接賦值,看看裡面怎麼處理的(將
runnable
轉成callable)
它實際上返回了乙個runnableadapter
runnableadapter實現
callable
介面,所以能夠賦值
callable
,構造方法只是內部賦值,重寫
了callable的
call
方法,裡面實際上就是將呼叫
runnable
的run
方法。這樣就做到了callable和
runnable
介面的統一。
然後我們在看到
這裡的execute需要傳遞
runnable
例項,但是我們都將他們處理成為
callable
了,其實這裡我們傳入的是
futuretask
,也就是
runnablefuture
的實現,而
runnablefuture
實現了runnable
介面,所以能夠傳入,而
futuretask
重寫了runnable
介面的run
方法。
這裡呼叫了callable的
call
方法拿到了返回值。
然後我們梳理一下,
我們在runable的
run方法中呼叫傳入的
callable
的call
方法,然後這裡的
callable
我們是先將
callable
或者runable
統一成callable
。然後我們看看去拿到返回值的方法
因為實際上是返回的runnablefuture的實現
futuretask
,那麼我們進入到
futuretask
的get
方法。這裡會有乙個執行緒問題,但我們先不管,先看看是返回的什麼。
這裡返回的是outcome,其實這裡的
outcome
就是前面
callabe.call
方法的返回值,
這樣就將值返回出去了,然後我們再來看看執行緒問題。
因為這是乙個多執行緒,然後我們通過get()方法得到返回值,那麼其中就會有乙個問題,那麼就是有可能我們呼叫的
get()
方法,但是
futuretask
的run
方法並沒有執行完,那麼我們就取不到值,那我們來看看它是怎麼保證能拿到值的。
這裡做了乙個判斷,就是乙個狀態的判斷,這裡的state使用了volatile關鍵字保證了變數的可見性,防止另乙個執行緒更改了狀態值,而該執行緒未return出迴圈。
重點來了,這裡是乙個死迴圈,然後判斷了乙個狀態,呼叫了locksupport.park方法讓這個執行緒阻塞,就是說你
get的時候,如果我沒執行完,那你就在這等著我執行完。
然後我們再來看看當run方法執行完的時候。
這裡呼叫了乙個locksupport.unpark方法,然後傳入了之前等待的執行緒
,這樣就能讓那個執行緒同行,繼續執行。
以上就是callable介面的核心流程,當然它內部還有許多判斷,畢竟是工業級**,但我們大概知道核心流程就ok了!
Callable原始碼分析
create by jh on 2018 4 9 乙個任務返回的結果可能丟擲異常,繼承者定義了乙個單例的沒有引數的方法被稱為call callable介面與runnable介面相似,這兩個都是為那些可能被其他執行緒的執行的例項的類設計的 runnable不會返回乙個結果,也不會跑出checked異常...
Callable原始碼分析
建立執行緒有3種方法 1 繼承thread介面,重寫run方法,呼叫start方法 public class mythread1 extends thread public static void main string args 2 實現runnable介面,重寫run方法 執行執行緒放入runn...
實現Callable介面的執行緒使用
專案中經常接觸執行緒,特別是在推送mq的時候,都是使用執行緒來執行操作。在這裡,用乙個簡單的例子來整理乙個很簡單的使用方法。如下 public class testthread catch interruptedexception e catch executionexception e class...