實現(xiàn)線程的方式,源碼分析:Runnable, Thread, Callable, Future, FutureTask

前言

在 Java 中,實現(xiàn)線程的方式主要有以下幾種方式:繼承 Thread, 實現(xiàn) Runnable 和實現(xiàn) Callable 這三種方式;采用哪種方式,主要根據(jù)實際情況而定,比如:因為 Java 是單繼承,所以如果定義的線程還有其他父類的話,就可以使用實現(xiàn) Runnable 的方式,如果定義的線程就只有 Thread 一個父類,就可以從用繼承 Thread 的方式來聲明線程;如果線程執(zhí)行后需要有返回值,則可以采用實現(xiàn) Callable 的方式來聲明線程。

Runnable

Runnable 的源碼如下:

Runnable 它是一個接口,只有一個 run 方法,當線程在執(zhí)行的時候,會自動的執(zhí)行該 run 方法,我們采用實現(xiàn) Runnable 的方式聲明線程的時候,就需要重寫該 run 方法;該方式需要使用 Thread 類的 start 方法來啟動線程。如下所示:

Thread

Thread 類本身就是一個線程,它實現(xiàn)了 Runnable 接口,它提供了很多的方法來控制線程的行為,類圖如下:

每個線程都有優(yōu)先級(priority),高優(yōu)先級的線程會優(yōu)于低優(yōu)先級的線程執(zhí)行,但并不是說高優(yōu)先級的線程一定在低優(yōu)先級的線程之前執(zhí)行,只是獲取到 CPU 的概率要大些。線程的優(yōu)先級共有 10 個級別,最低級別為1,默認的級別為5,最高級別為10。

當Java虛擬機啟動時,通常會有一個非守護程序線程(通常調(diào)用某個指定類的main方法)。 當在遇到如下任意情況之前,Java虛擬機會繼續(xù)執(zhí)行線程:

1. 調(diào)用 Runtime 類的 exit 方法,并且安全管理器允許執(zhí)行退出操作

2. 所有非守護線程都已“死亡”

3. run 方法執(zhí)行完畢

4. run 方法拋出異常。

下面來看下 Thread 類的源碼,只會選一些常見的進行分析:

下面是 Thread 的一些常見方法:

yield()

yield 方法會告訴線程調(diào)度器,當前線程愿意放棄CPU的使用權(quán),把CPU讓給其他線程執(zhí)行,當前線程會從執(zhí)行狀態(tài)變?yōu)榭蓤?zhí)行狀態(tài);但是,調(diào)度器可能會忽略該消息,也就是說,yield 方法有意愿放棄CPU的使用權(quán),但是還得看調(diào)度器是否同意,即使 yield 已經(jīng)成功的放棄了CPU的使用權(quán),但是在下一輪調(diào)度的時候,還是會調(diào)度到它,讓它繼續(xù)執(zhí)行;yield 方法主要是用來保證其他線程有機會執(zhí)行而不至于會導致饑餓。一般很少使用該方法,但是它對于調(diào)試和測試可能很有用。

測試:

sleep()?

sleep 方法導致當前正在執(zhí)行的線程休眠(暫時停止執(zhí)行)指定的毫秒數(shù), 該線程不會釋放已經(jīng)擁有的鎖。 如果其他的線程中斷了一個休眠的線程,sleep方法會拋出Interrupted Exception。

start()

start 方法是用來啟動一個線程,當調(diào)用 start 方法后,JVM 會自動去執(zhí)行當前線程的 run 方法,從上述源碼中可以看到,start 會執(zhí)行 start0 方法,而 start0 方法是一個本地方法,run 方法應該在里面調(diào)用的吧。

start 方法只能調(diào)用一次,多次調(diào)用會出錯。

interrupt()

interrupt 方法中斷當前線程。如果在調(diào)用 wait 或 join 時阻塞了這個線程,那么它的中斷狀態(tài)將被清除,它將收到一個?InterruptedException。如果此線程在I / O操作中被阻塞,那么通道將關(guān)閉,線程的中斷狀態(tài)將被設置,并且線程將接收到?ClosedByInterruptExcetion。如果上述操作沒有拋出異常,則將設置該線程的中斷狀態(tài)。

interrupt方法并不是強制終止線程,它只能設置線程的中斷狀態(tài)

interrupted()

測試當前線程是否已經(jīng)中斷。線程的中斷狀態(tài)?由該方法清除。換句話說,如果連續(xù)兩次調(diào)用該方法,則第二次調(diào)用將返回 false(在第一次調(diào)用已清除了其中斷狀態(tài))

isInterrupted()

測試線程是否已經(jīng)中斷。線程的中斷狀態(tài)不受該方法的影響。

join()

join 方法把指定線程加入到當前線程中執(zhí)行,可以將兩個交替執(zhí)行的線程合并為順序執(zhí)行的線程。比如在線程B中調(diào)用了線程A的Join()方法,直到線程A執(zhí)行完畢后,才會繼續(xù)執(zhí)行線程B。

以上就是 Thread 類中的常見方法。

既然說到 sleep 方法,就會想到 Object 的 wait 方法。wait 方法也會是線程暫停執(zhí)行,直到由?notify 或 notifyAll 進行喚醒。調(diào)用 wait 方法后,線程會釋放掉鎖。

Callable

Callable 也可以用來實現(xiàn)線程,采用?Callable 方式執(zhí)行線程,我們可以得到線程的一個執(zhí)行結(jié)果,線程的執(zhí)行結(jié)果通過?Future 進行返回;

Callable 和 Runnable? 類似,都是為了線程而設計,但是 Runnable 的 run 方法執(zhí)行線程后不能返回結(jié)果,也不能拋出異常;而 Callable 的 call 方法可以有返回值和拋出異常。

先看下它的源碼實現(xiàn):

Callable 需要配合?ExecutorService 來進行使用,它提供了一系列的的 submit 來執(zhí)行:

?Future

一個 Future 代表著一個異步計算結(jié)果,它提供了一些方法去檢查計算是否完成,等待其完成,以及檢索計算結(jié)果等。接下來看下它的接口聲明:

看下它的一個使用:

FutureTask

FutureTask 提供了 Future 類的一個基本實現(xiàn),它的類圖如下:

可以看到,F(xiàn)utureTask 還實現(xiàn)了 Runnable 接口,所以它既可以作為Runnable被線程執(zhí)行,又可以作為Future得到Callable的返回值。

以上就是實現(xiàn)線程的幾種方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 進程和線程 進程 所有運行中的任務通常對應一個進程,當一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    勝浩_ae28閱讀 5,260評論 0 23
  • ??一個任務通常就是一個程序,每個運行中的程序就是一個進程。當一個程序運行時,內(nèi)部可能包含了多個順序執(zhí)行流,每個順...
    OmaiMoon閱讀 1,809評論 0 12
  • 進程和線程 進程 所有運行中的任務通常對應一個進程,當一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    小徐andorid閱讀 2,995評論 3 53
  • 本文是我自己在秋招復習時的讀書筆記,整理的知識點,也是為了防止忘記,尊重勞動成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 11,646評論 4 56
  • 喜歡這樣的天氣,絲絲涼意,好像要下雨,好像又不下雨,輕快的南山南的旋律,希望每一天的生活都可如此美好
    DISPARIY閱讀 268評論 0 0

友情鏈接更多精彩內(nèi)容