目錄
- 一、前言
- 二、`JConsole `使用教程
- 二、線程的基本狀態
- 2.1新建狀態(New)
- 2.2就緒狀態(Ready)
- 2.3運行狀態(Running)
- 2.4 阻塞狀態(Blocked)
- 2.5. 等待狀態(Waiting)
- 2.6 等待狀態(TIMED_WAITING)
- 2.7終止狀態(TERMINATED)
- 二、線程狀態的轉換
- 三、線程安全與狀態管理
- 四、總結
一、前言
在操作系統和并發編程中,線程作為最小的執行單位,其生命周期中會經歷多個不同的狀態。理解這些狀態及其轉換非常重要,因為它們直接關系到程序的正確性和性能。本文將詳細解析線程的各個狀態及其轉換關系。
二、JConsole
使用教程
JConsole 是一種 Java 監控和管理控制臺工具,可以用于監視 Java 虛擬機(JVM)的性能和資源利用情況。它提供了一種圖形化界面,可以實時查看 JVM 的運行狀態、內存使用情況、線程活動、垃圾回收等信息,以及執行一些管理操作
1.啟動
JConsole
JConsole 是包含在 JDK 中的一個工具,因此首先要確保已經安裝了 JDK。然后,找到jconsole.exe
的位置然后 雙擊 jconsole.exe 啟動 JConsole。
2.連接到 Java 進程
啟動 JConsole 后,會彈出一個界面,顯示所有正在運行的 Java 進程。選擇要監控的 Java 進程,并點擊連接按鈕
我們先簡單看一個代碼:
public class Tsleep {public static void main(String[] args) {Thread t=new Thread(()->{try {Thread.sleep(3000);System.out.println("運行線程...");} catch (InterruptedException e) {e.printStackTrace();}},"T1");t.start();System.out.println("main....線程運行...");}
}
啟動項目:然后打開jconsoel
選中我們需要觀察的線程。
3.本地連接
在本地進程中會展示出當前計算機所有正在運行的 Java 程序,只需選中雙擊進入,再點擊“不安全的連接”即可進入到監聽界面
然后我們就可以通過這個jconsole
來更好的觀察線程狀態了。
二、線程的基本狀態
2.1新建狀態(New)
- 當線程被創建時,線程處于新建狀態。
- 此時線程尚未開始執行,只是被操作系統或運行時環境識別為一個線程對象。
- 例如:使用
new Thread()
創建一個線程實例,線程處于新建狀態。
NEW: 安排了工作, 還未開始行動。
public class Tsleep {public static void main(String[] args) {Thread t=new Thread(()->{try {Thread.sleep(10000);System.out.println("運行線程...");} catch (InterruptedException e) {e.printStackTrace();}},"T1");System.out.println(t.getState());t.start();}
}
線程在start之前的狀態。
可以看到NEW
狀態被打印出來了,這就是新建狀態。
2.2就緒狀態(Ready)
- 線程被操作系統的調度器識別為可執行狀態,等待 CPU 資源。
- 此時線程已經被初始化并且具備了運行條件。
當線程被創建(如 new Thread())后,線程處于 Ready 狀態,但尚未開始執行。
例如:
Thread thread = new Thread(() -> {System.out.println("Hello, Thread!");
});
// 此時線程處于 Ready 狀態,但尚未調用 start()
2.3運行狀態(Running)
線程獲得 CPU 時間片,開始執行線程的
run()
方法。
這是線程執行任務的核心狀態。
RUNNABLE: 可工作的. 又可以分成正在工作中和即將開始工作
public class Dom12 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{while (true){//這里什么都不做}});t.start();//真正工作的狀態System.out.println(t.getState());}
}
Ready 狀態與 Running 狀態的區別
特性 | Ready 狀態(就緒狀態) | Running 狀態(運行狀態) |
---|---|---|
CPU 資源 | 等待 CPU 資源 | 獲得 CPU 資源,正在執行任務 |
執行狀態 | 未執行 | 執行中 |
進入方式 | 調用 start() 、從阻塞/等待恢復 | 調度器選擇并分配 CPU 時間片 |
退出方式 | 獲得 CPU 后進入 Running 狀態 | 時間片用完或被中斷,返回 Ready 狀態 |
2.4 阻塞狀態(Blocked)
- 線程因等待某些資源(如 I/O、鎖等)而暫停執行。
- 阻塞狀態的線程不在就緒隊列中,直到等待的資源可用才會解除阻塞。
- 例如:線程嘗試獲取一個已經被其他線程占用的鎖時,會進入阻塞狀態。
package tset1;public class Tsleep {public static void main(String[] args) throws InterruptedException {// 共享的鎖對象Object lock = new Object();
// 線程 1Thread thread1 = new Thread(() -> {synchronized (lock) {System.out.println("Thread1: 已進入同步塊");try {for (int i = 0; i < 5; i++) {System.out.println("Thread1: 迭代 " + i);Thread.sleep(3000); // 睡眠3000毫秒}} catch (InterruptedException e) {System.out.println("Thread1: 被中斷");}System.out.println("Thread1: 已退出同步塊");}},"T1");// 線程 2Thread thread2 = new Thread(() -> {synchronized (lock) {System.out.println("Thread2: 已進入同步塊");try {for (int i = 0; i < 5; i++) {System.out.println("Thread2: 迭代 " + i);Thread.sleep(3000); // 睡眠 3000 毫秒}} catch (InterruptedException e) {System.out.println("Thread2: 被中斷");}System.out.println("Thread2: 已退出同步塊");}},"T2");// 啟動兩個線程thread1.start();thread2.start();// 主線程等待兩個子線程完成try {thread1.join();thread2.join();} catch (InterruptedException e) {System.out.println("Main: 在等待子線程完成時被中斷");}}
}
代碼解釋
共享鎖對象:
Object lock = new Object(); 定義了一個共享的鎖對象,用于在多個線程之間同步。
線程創建:
創建了兩個線程 thread1 和 thread2,它們都將嘗試獲取鎖 lock。
在 synchronized (lock) 塊內,線程將執行一個循環,睡眠500毫秒,模擬執行任務。
啟動線程:
thread1.start(); 和 thread2.start(); 啟動了兩個線程,讓它們競爭鎖 lock。
主線程等待:
thread1.join();和thread2.join(); 確保主線程在等待兩個子線程完成后再退出。
2.5. 等待狀態(Waiting)
WAITING 狀態是無限等待狀態,直到被其他線程喚醒。
public class Dom14 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{while (true){//System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new NullPointerException();}}});t.start();//join() 會出現WAITING狀態 --死等t.join();System.out.println(t.getState());}
}
通過控制臺觀察不到,因為出現了死等所以,所以jconsole
進行觀察:
阻塞狀態與等待狀態的區別
2.6 等待狀態(TIMED_WAITING)
TIMED_WAITING 狀態是有限等待狀態,線程會在指定時間后自動退出。
public class Dom13 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{while (true){//System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new NullPointerException();}}});t.start();Thread.sleep(100);//指定時間的阻塞 TIMED_WAITING 狀態System.out.println(t.getState());//join(時間)也會進入TIMED_WAITING 狀態t.join(100);System.out.println(t.getState());}
}
2.7終止狀態(TERMINATED)
- 線程完成執行或 debido a una interrupción external? 執行結束。
- 一旦線程終止,其資源會被操作系統回收。
TERMINATED: 工作完成了.
public class Dom11 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{System.out.println("hello thread");});t.start();Thread.sleep(1000);//內核當中的線程已經結束了(工作結束了)System.out.println(t.getState());}
}
二、線程狀態的轉換
線程狀態之間的轉換是由操作系統的調度器和線程自身的行為決定的。以下是線程狀態轉換的常見情況:
?家不要被這個狀態轉移圖嚇到,我們重點是要理解狀態的意義以及各個狀態的具體意思。
例子:(銀行的例子)
剛把李四、王五找來,還是給他們在安排任務,沒讓他們行動起來,就是 NEW 狀態;
當李四、王五開始去窗口排隊,等待服務,就進?到 RUNNABLE 狀態。該狀態并不表示已經被銀行工作?員開始接待,排在隊伍中也是屬于該狀態,即可被服務的狀態,是否開始服務,則看調度器的調度;
當李四、王五因為?些事情需要去忙,例如需要填寫信息、回家取證件、發呆?會等等時,進入BLOCKED 、 WATING 、 TIMED_WAITING 狀態;如果李四、王五已經忙完,為 TERMINATED 狀態。
- 就緒 → 運行
- 操作系統的調度器選擇一個就緒狀態的線程,并分配 CPU 時間片。
- 例如:
Thread thread = new Thread(); thread.start();
-
運行 → 就緒
- 線程的 CPU 時間片用完,被調度器剝奪 CPU 使用權。
- 例如:操作系統使用時間片調度,線程的時間片到期后會被暫停。
-
運行 → 阻塞
- 線程在執行過程中等待某些資源(如 I/O 或鎖),主動放棄 CPU。
例如:線程嘗試獲取一個被其他線程占用的鎖:
java synchronized (lock) { //如果 lock 已被另一個線程占用,此線程將進入阻塞狀態 }
- 運行 → 等待
- 線程主動調用某些方法(如
sleep()
),等待特定條件滿足。
** 例如:**
java Thread.sleep(1000); //線程進入等待狀態,等待 1 秒
- 阻塞/等待 → 就緒
- 阻塞狀態的線程等到所需資源可用(如鎖被釋放)。
- 等待狀態的線程等到超時或被其他線程喚醒。
- 例如:
// 阻塞狀態的線程獲取鎖后會自動轉移到就緒狀態
三、線程安全與狀態管理
在多線程編程中,線程狀態的管理直接關系到程序的正確性和性能。以下是需要注意的事項:
- 避免長時間占用 CPU
- 長時間占用 CPU 的線程會導致其他線程饑餓。
- 建議使用
yield()
或sleep()
方法讓出 CPU。
- 合理加鎖和解鎖
- 鎖的不當使用可能導致線程長時間阻塞。
- 例如:在持有鎖時避免執行耗時操作。
- 正確使用等待/通知機制
- 使用
wait()
和notify()
方法可以更高效地管理線程間的協作。- 例如:實現生產者-消費者模式時,使用等待隊列管理線程狀態。
四、總結
在本文中,我們將通過JConsole這款強大的工具,深入探索Java多線程的核心知識。從線程的基本狀態(如新建、就緒、運行、阻塞、等待和終止)到線程狀態之間的轉換機制,幫助開發者更好地理解和管理線程。通過實踐性的教程,讀者將學會如何利用JConsole監控和調試線程,從而優化應用程序的性能和穩定性。這篇文章適合Java開發人員和對并發編程感興趣的學習者,旨在提供一份清晰易懂的指南,助力在多線程編程中游刃有余
如果您需要更深入的內容或具體案例,可以在留言區告訴我!