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