前言
在 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)線程的幾種方式。