Java多線程帶返回值的Callable接口java
在面試的時候,有時候是否是會遇到面試會問你,Java中實現多線程的方式有幾種?你知道嗎?你知道Java中有能夠返回值的線程嗎?在具體的用法你知道嗎?若是兩個線程同時來調用同一個計算對象,計算對象的call方法會被調用幾回你知道嗎?若是這些你知道,那麼凱哥(凱哥Java:kaigejava)恭喜你,本文你能夠不用看了。若是你不知道這些,那麼凱哥一樣要恭喜你,看了凱哥這篇文章以後,就知道這些了。來看看這篇文章咱們能學到什麼面試
本節主要內容設計模式
一:三種獲取多線程的的寫法多線程
二:分析第三種寫法的思想思路-使用了適配器模式ide
三:第三種方法怎麼使用spa
四:多個線程調用同一個futrueTask後,future的call方法會被執行幾回?線程
咱們已經知道Java中經常使用的兩種線程實現方式:分別是繼承Thread類和實現Runnable接口。設計
以下圖:3d
從上圖中,咱們能夠看到,第三種實現Callable接口的線程,並且還帶有返回值的。咱們來對比下實現Runnable和實現Callable接口的兩種方式不一樣點:orm
1:須要實現的方法名稱不同:一個run方法,一個call方法
2:返回值不一樣:一個void無返回值,一個帶有返回值的。其中返回值的類型和泛型V是一致的。
3:異常:一個無需拋出異常,一個須要拋出異常。在後面使用場景中,凱哥會講解到的
咱們先來看看Thread類:這個類是Java中獲取線的對象。通常咱們獲取並啓動線程調用的是start方。從JDK的API中,咱們能夠看到,start方法是JVM調用的
再來看看常寫的方法:
Thread t1 = new Thread();
t1.start();
咱們來看看其構造器:
三個構造器:無參構造器、一個參數構造器和兩個參數構造器。可是就沒有咱們Callable做爲參數的構造器。那麼,咱們想要獲取到線程,經過callable怎麼獲取呢 ?
就拿凱哥剛到帝都找房子的案例來講吧。凱哥剛到帝都人生地不熟的,想要找房子怎麼辦呢?
房東有房子,凱哥想要找房子,那麼這兩個原本沒有直接聯繫的經過房屋中介公司就產生了關係。凱哥要想找到房子,先要找到房屋中介公司,而後房屋中介公司又有房東的聯繫方式,而後凱哥就經過中介公司租到房東的房子了(中介公司從中間收取手續費)。這個現實案例我想你們都遇到過吧。
好了,咱們經過上面案例在回到Thread類和Callable類來看,這兩個對象之間有沒有中間商呢?
從上圖中咱們發現,Threa的有參構造都是Runnable接口的。那麼,有沒有一個類既實現了Runnable接口又實現了Callable接口呢?若是有這樣的一個類存在的話,callable就與Thread類產生了關係,就可使用了。咱們來看看Runnable接口的API吧
咱們能夠已知的子類有個RunnableFuture<V>。這個接口的形式和咱們Callable接口的形式很像啊,以下圖:
咱們從上圖對比中能夠看到,兩個接口中的V都是方法返回值的類型。那麼Callable和Thread兩個類之間的橋樑就是這個類(RunnableFuture)或者是這個類的子類呢?咱們接着來看看這個對象的子類。
其中SwingWorker這個咱們不用看。這個是圖形化的Swing相關的。咱們不用,那麼咱們就來看看FutureTask這個類:
從這個類中,咱們能夠看到其實現了Runnable接口,在構造器中,咱們能夠看到:
FutureTask(Callable<V> callable)
建立一個 FutureTask ,它將在運行時執行給定的 Callable 。
以下圖:
這個類是否是既有Callable接口又有Runnable接口了?這個就是咱們的中間類。
因此,咱們經過上面分析就能夠獲得下圖的關係:
這種就是設計模式中的適配器模式(PS:在後面,凱哥會從新分享23種設計模式的)。在Java中的中間商是不會賺取差價的,放心。O(∩_∩)O
知道了Callable的設計思路以後,那麼咱們怎麼來使用呢?
步驟:
1:一樣建立一個類實現Callable接口;
2:經過futureTask類使用其傳遞Callable接口做爲參數的有參構造方法;
3:使用thread的有參構造;
4:t1.start()啓動線程
5:啓動線程後,經過futureTask.get()方法獲取到線程的返回值。
以下圖:
咱們來查看運行結果:
進入了callable接口且獲取到了返回值:1024.說明callable的使用正確了。
須要注意:futrueTask.get()方法放到最後,這樣就不會影響主線程了。若是get方法放在前面的話,會形成主線程阻塞,等到futrueTask運行完成以後,才繼續執行本身的邏輯。這樣就失去了開啓線程的意義了!!!
咱們能夠看到t1和t2都start了,說明兩個線程都啓動了。並且都是用的是同一個futureTask對象。問題:MyThread3中的call方法會被調用幾回呢?