比如有這么個(gè)需求:有線程A、B。A線程是搬磚,B線程是蓋房,B必須在A完成后執(zhí)行。怎么辦?
一、用Thread的join方法

join中參數(shù)為啟動(dòng)banzhuanThread的線程等待banzhuanThread執(zhí)行的時(shí)間,時(shí)間到達(dá)后,代碼接著往下執(zhí)行。參數(shù)缺省時(shí)會(huì)一直等待時(shí)間無(wú)窮,直到執(zhí)行完成。
如果搬磚的人半路不干了(線程A未按理想情況完成),磚沒(méi)搬完,就不能開(kāi)始蓋房,此時(shí)join方法就不適合這種場(chǎng)景了。接下來(lái)就需要用到Future/FutureTask,它們能告訴你搬磚是正常完成還是其他特殊情況。
二、用Future或FutureTask:
先簡(jiǎn)單對(duì)比一下Future和FutureTask:
相同點(diǎn):
1)、Future和FutureTask都可以通過(guò)調(diào)用get(),獲得Callable中返回的結(jié)果,并且該方法是線程阻塞的;
不同點(diǎn):
1)、Future是個(gè)接口,用來(lái)展現(xiàn)異步執(zhí)行的結(jié)果;
2)、FutureTask是個(gè)類(lèi),實(shí)現(xiàn)了RunnableFuture接口(RunnableFuture又同時(shí)繼承了Runnable和Future接口);不難看出,F(xiàn)utureTask比Future多了個(gè)Runnable。這也就意味著在使用上存在一些的不同。
再來(lái)看兩個(gè)簡(jiǎn)單的例子:
首先我們自定義一個(gè)BanzhuanCallable實(shí)現(xiàn)Callable接口。Callable接口類(lèi)似Runnable,兩者都是用于多線程。最重要區(qū)別是:Runnanble不返回線程執(zhí)行結(jié)果并且也無(wú)法拋出受檢異常。而,Callabel卻可以。

1、用FutureTask實(shí)現(xiàn):
由于FutureTask實(shí)現(xiàn)了Runnable接口,所以可以直接傳參給Thread構(gòu)造方法,并調(diào)用start執(zhí)行。

2、用Future實(shí)現(xiàn):
Future實(shí)現(xiàn)需用到線程池(這里為了方便直接用的Executors.newCachedThreadPool(),大家可以自行單例化一下)。

當(dāng)然,例子1中new?Thread也可以換成線程池,調(diào)用execute/submit方法。
補(bǔ)充一個(gè)知識(shí)點(diǎn):
線程池的submit傳參可以是Runnable,也可以是Callable。最后都會(huì)轉(zhuǎn)換成RunnableFuture(FutureTask就是實(shí)現(xiàn)的這個(gè)接口)。


上面講了這么多,提到Callable、Runnable、Future、FutureTask、線程池submit方法。這幾者之間的關(guān)系大家結(jié)合上面例子,稍微思考一下,應(yīng)該就很清晰了。
希望本文能夠幫到大家!