線程有五個狀態,分別是新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)。
新建和就緒
程序使用new會新建一個線程,new出的對象跟普通對象一樣,JVM會為其分配內存,初始化成員變量等,此時線程並沒有運行,而是就是新建狀態。
當線程對象調用start后,線程將進入就緒狀態。JVM會為其創建函數調度棧和計數器,但此時線程依然沒有運行,而是等待獲取CPU執行片
下面的例子可以證明當線程對象調用start后,並不一定立即執行,
for (int i=0; i<50; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
SecondThread st = new SecondThread();
new Thread(st, "new thread 1").start();
}
}
上面是在main中創建子線程,下面是運行結果,
... main 18 main 19 main 20 main 21 main 22 new thread 1 0 main 23 new thread 1 1 main 24 new thread 1 2 main 25 ...
從上面的運行結果可以看到,原本在main中i=20的時候新建了一個子線程,並立即調用了start()使線程進入就緒狀態,但是一直等到i=22的時候,子線程才開始運行,所以子線程何時會開始執行取決於CPU執行片的分配,由JVM調度器決定。
運行和阻塞狀態
當就緒狀態的線程獲取了CPU執行片的之后,就進入運行狀態,但是在執行過程中,可能會因為以下原因使線程進入阻塞狀態,
- CPU執行片已經用完,JVM切換到其他線程執行
- 線程調用sleep()
- 線程調用了阻塞IO方法,該方法返回之前,線程會一直阻塞
- 線程試圖獲取被其他線程持有的同步監視器
- 線程在等待某個通知
- 程序調用了線程的suspend()將線程掛起。(容易死鎖,不推薦)
線程從運行進入阻塞狀態之后,接着只能繼續阻塞或者再次進入就緒狀態,下面情況會使線程由阻塞狀態重新進入就緒狀態,
- 線程調用的slee()經過了指定時間
- 線程調用的阻塞IO方法返回
- 線程成功獲取同步監視器
- 線程收到其他線程發出的通知
- 被掛起(suspend)的線程又被程序調用了resume方法
下圖演示了線程狀態轉換過程,

注意從上圖可知,
線程從阻塞狀態只能進入就緒狀態,
通常情況下,就緒狀態和運行狀態的轉換是不受程序控制的,而是由JVM線程調度機制控制的
yield()方法可以讓運行狀態的線程進入就緒狀態
線程死亡
線程結束后就處於死亡狀態,線程會以如下三種方式結束,
- run()或call()正常執行完成,線程正常結束
- 線程拋出一個未捕獲的Exception或Error
- 直接調用線程的stop()方法結束線程,容易死鎖
注意,子線程一旦啟動,其地位和主線程是一樣的,所以一旦主線程結束了,子線程不會受影響,不會跟着結束
線程對象的isAlive()方法在就緒,運行,阻塞時返回true,在新建,死亡時返回false
對已經死亡的線程調用start()是無效的,會拋出異常。 死亡的線程不可再次作為線程來執行。
對於新建的線程,調用兩次start()方法也會拋出異常
