源碼:callable接口的底層實現


在使用線程池的時候,我們需要使用到callable接口,那我們來看一下calllable的底層是怎么實現,並且有返回值的。

首先我們看一下調用。

 

 

 

 

ThreadPoolExcutor並沒有實現submit方法,那么肯定是它的父類實現的。

 

 

 

 

 

如願以償在AbstractExecutorService中找到了submit方法,找到對應的方法,根據我們傳入的callable接口找到。

 

 

 

在上面我們可以看到我們將callable或者runnable傳入進去給我們返回了一個RunnableFuture,

實際上是返回了一個它的實現FutureTask,這就是核心類。

 

 

 

這里實際上做的是callable賦值,第一個構造就是直接賦值給callable就行,但是第二個構造方法是傳入的runnable,並不能直接賦值,看看里面怎么處理的(runnable轉成callable)

 

 

 

它實際上返回了一個RunnableAdapter

 

 

RunnableAdapter實現callable接口,所以能夠賦值callable,構造方法只是內部賦值,重寫callablecall方法,里面實際上就是將調用runnablerun方法。

這樣就做到了callablerunnable接口的統一。

 

 

 

 

然后我們在看到

 

 

這里的execute需要傳遞runnable實例,但是我們都將他們處理成為callable了,其實這里我們傳入的是FutureTask,也就是RunnableFuture的實現,而RunnableFuture實現了runnable接口,所以能夠傳入,而FutureTask重寫了runnable接口的run方法。

 

 

這里調用了callablecall方法拿到了返回值。

然后我們梳理一下,  我們在runablerun方法中調用傳入的callablecall方法,然后這里的callable我們是先將callable或者runable統一成callable

 

然后我們看看去拿到返回值的方法

 

 

因為實際上是返回的RunnableFuture的實現FutureTask,那么我們進入到FutureTaskget方法。

 

 

 

這里會有一個線程問題,但我們先不管,先看看是返回的什么。

這里返回的是outcome,其實這里的outcome就是前面callabe.call方法的返回值,

 

 

 

 

 

這樣就將值返回出去了,然后我們再來看看線程問題。

因為這是一個多線程,然后我們通過get()方法得到返回值,那么其中就會有一個問題,那么就是有可能我們調用的get()方法,但是futureTaskrun方法並沒有執行完,那么我們就取不到值,那我們來看看它是怎么保證能拿到值的。

 

 

這里做了一個判斷,就是一個狀態的判斷,這里的state使用了volatile關鍵字保證了變量的可見性,防止另一個線程更改了狀態值,而該線程未return出循環。

重點來了,這里是一個死循環,然后判斷了一個狀態,調用了LockSupport.park方法讓這個線程阻塞,就是說你get的時候,如果我沒執行完,那你就在這等着我執行完。

然后我們再來看看當run方法執行完的時候。

 

 

 

 

 

這里調用了一個LockSupport.unpark方法,然后傳入了之前等待的線程,這樣就能讓那個線程同行,繼續執行。

 

以上就是callable接口的核心流程,當然它內部還有許多判斷,畢竟是工業級代碼,但我們大概知道核心流程就ok了!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM