1、五種狀態
這是從 操作系統
-
【初始狀態】僅是在語言層面創建了線程對象,還未與操作系統線程關聯
-
【可運行狀態】(就緒狀態)指該線程已經被創建(與操作系統線程關聯),可以由 CPU 調度執行
-
【運行狀態】指獲取了 CPU 時間片運行中的狀態
-
當 CPU 時間片用完,會從【運行狀態】轉換至【可運行狀態】,會導致線程的上下文切換
-
-
【阻塞狀態】
-
如果調用了阻塞 API,如 BIO 讀寫文件,這時該線程實際不會用到 CPU,會導致線程上下文切換,進入【阻塞狀態】
-
等 BIO 操作完畢,會由操作系統喚醒阻塞的線程,轉換至【可運行狀態】
-
與【可運行狀態】的區別是,對【阻塞狀態】的線程來說只要它們一直不喚醒,調度器就一直不會考慮調度它們
-
-
【終止狀態】表示線程已經執行完畢,生命週期已經結束,不會再轉換爲其它狀態
2、六種狀態
這是從 Java API 層面來描述的,根據 Thread.State 枚舉,分爲六種狀態
-
NEW
線程剛被創建,但是還沒有調用start()
方法 -
RUNNABLE
(RUNNING)當調用了start()
方法之後,注意,Java API 層面的RUNNABLE
狀態涵蓋了 操作系統 層面的【可運行狀態】、【運行狀態】和【阻塞狀態】(由於 BIO 導致的線程阻塞,在 Java 裏無法區分,仍然認爲是可運行) -
BLOCKED
,WAITING
,TIMED_WAITING
都是 Java API 層面對【阻塞狀態】的細分,後面會在狀態轉換一節詳述 -
TERMINATED
當線程代碼運行結束
代碼示例
@Slf4j(topic = "c.TestState")
public class TestState {
public static void main(String[] args) throws IOException {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("running...");
}
}; // 未start 所以日誌未打印
Thread t2 = new Thread("t2") {
@Override
public void run() {
while(true) { // runnable
}
}
};
t2.start();
Thread t3 = new Thread("t3") {
@Override
public void run() {
log.debug("running...");
}
};
t3.start();
Thread t4 = new Thread("t4") {
@Override
public void run() {
synchronized (TestState.class) {
try {
Thread.sleep(1000000); // timed_waiting
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t4.start();
Thread t5 = new Thread("t5") {
@Override
public void run() {
try {
t2.join(); // waiting
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t5.start();
Thread t6 = new Thread("t6") {
@Override
public void run() {
synchronized (TestState.class) { // blocked
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t6.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("t1 state {}", t1.getState());
log.debug("t2 state {}", t2.getState());
log.debug("t3 state {}", t3.getState());
log.debug("t4 state {}", t4.getState());
log.debug("t5 state {}", t5.getState());
log.debug("t6 state {}", t6.getState());
System.in.read();
}
}
輸出