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

前言

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

Runnable

Runnable 的源碼如下:

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

Thread

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

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

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

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

2. 所有非守護(hù)線程都已“死亡”

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

4. run 方法拋出異常。

下面來(lái)看下 Thread 類的源碼,只會(huì)選一些常見(jiàn)的進(jìn)行分析:

下面是 Thread 的一些常見(jiàn)方法:

yield()

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

測(cè)試:

sleep()?

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

start()

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

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

interrupt()

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

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

interrupted()

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

isInterrupted()

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

join()

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

以上就是 Thread 類中的常見(jiàn)方法。

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

Callable

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

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

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

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

?Future

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

看下它的一個(gè)使用:

FutureTask

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

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

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

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

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

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

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