前言
Java中的線程生命周期是多線程開發(fā)的核心概念。了解線程的生命周期以及它們?nèi)绾芜M行狀態(tài)轉(zhuǎn)換對于編寫有效且無錯誤的多線程程序至關(guān)重要。
一、線程的生命周期
Java線程主要有以下幾個狀態(tài),這些狀態(tài)定義在Thread.State枚舉類中:
-
新建狀態(tài)(New):當(dāng)我們創(chuàng)建一個新的線程實例時,線程就處于新建狀態(tài)。這時候線程的
start()
方法還未被調(diào)用,線程對象還未開始執(zhí)行。在這個狀態(tài)下,Java虛擬機(JVM)已經(jīng)為此線程分配了必要的內(nèi)存。Thread t = new Thread(); // 線程此時處于New狀態(tài)
-
就緒狀態(tài)(Runnable):當(dāng)線程對象調(diào)用了
start()
方法后,該線程就處于就緒狀態(tài)。就緒狀態(tài)的線程在獲得CPU時間片后就可以開始運行。這個狀態(tài)的線程位于可運行線程池中,等待被線程調(diào)度選中,獲得CPU的使用權(quán)。t.start(); // 線程此時處于Runnable狀態(tài)
-
運行狀態(tài)(Running):線程獲取到CPU時間片后,就進入運行狀態(tài),開始執(zhí)行
run()
方法中的代碼。值得注意的是,代碼執(zhí)行的實際速度和效率與處理器的速度以及多核處理器的核數(shù)有關(guān)。public void run() { System.out.println("Thread is running."); } // 如果此時這個方法正在執(zhí)行,那么線程就處于Running狀態(tài)
-
阻塞狀態(tài)(Blocked):當(dāng)一個線程試圖獲取一個內(nèi)部的對象鎖(也就是進入一個
synchronized
塊),而該鎖被其他線程持有,則該線程進入阻塞狀態(tài)。阻塞狀態(tài)的線程在鎖被釋放時,將會進入就緒狀態(tài)。synchronized(object) { // 如果此時object的鎖被其他線程持有,那么線程就處于Blocked狀態(tài) }
-
等待狀態(tài)(Waiting):線程通過調(diào)用其自身的
wait()
方法、join()
方法或LockSupport.park()
方法,或者通過調(diào)用其他線程的join()
方法,可以進入等待狀態(tài)。在等待狀態(tài)的線程不會被分配CPU時間片,它們只能通過被其他線程顯式喚醒進入就緒狀態(tài)。t.wait(); // 線程此時處于Waiting狀態(tài) t.join(); // 線程此時處于Waiting狀態(tài)
-
超時等待狀態(tài)(Timed Waiting):當(dāng)線程調(diào)用了
sleep(long ms)
,wait(long ms)
,join(long ms)
,或者LockSupport.parkNanos()
,LockSupport.parkUntil()
等具有指定等待時間的方法,線程就會進入超時等待狀態(tài)。當(dāng)超時時間到達后,線程會自動返回到就緒狀態(tài)。Thread.sleep(1000); // 線程此時處于Timed Waiting狀態(tài)
-
終止?fàn)顟B(tài)(Terminated):當(dāng)線程的
run()
方法執(zhí)行完畢,或者線程中斷,線程就會進入終止?fàn)顟B(tài)。在這個狀態(tài)下,線程已經(jīng)完成了它的全部工作。// 當(dāng)run()方法執(zhí)行完畢,線程處于Terminated狀態(tài) public void run() { System.out.println("Thread is running."); }
這些狀態(tài)之間的轉(zhuǎn)換,通過各種方法的調(diào)用來實現(xiàn)。接下來我們將看到這些狀態(tài)轉(zhuǎn)換的具體情況。
二、線程狀態(tài)轉(zhuǎn)換
線程狀態(tài)的轉(zhuǎn)換是非常重要的一部分,了解狀態(tài)之間的轉(zhuǎn)換有助于我們更好地理解和掌握線程的行為。下面,我們來看看Java中各種線程狀態(tài)的轉(zhuǎn)換情況。
-
新建狀態(tài)轉(zhuǎn)就緒狀態(tài):當(dāng)線程對象被創(chuàng)建后,其進入新建狀態(tài)。此時,通過調(diào)用線程對象的
start()
方法,可以讓線程進入就緒狀態(tài),等待系統(tǒng)的線程調(diào)度器進行調(diào)度。Thread t = new Thread(); // 新建狀態(tài) t.start(); // 調(diào)用start()方法,線程進入就緒狀態(tài)
-
就緒狀態(tài)轉(zhuǎn)運行狀態(tài):線程調(diào)度器從就緒隊列中選擇一個線程,分配給它CPU資源,這個線程就由就緒狀態(tài)變?yōu)檫\行狀態(tài)。
-
運行狀態(tài)轉(zhuǎn)就緒狀態(tài):當(dāng)一個運行狀態(tài)的線程調(diào)用了
yield()
方法,或者該線程的運行時間超過了系統(tǒng)規(guī)定的時間片,線程就會釋放CPU資源,自己由運行狀態(tài)變回就緒狀態(tài),重新等待系統(tǒng)調(diào)度。Thread.yield(); // 調(diào)用yield()方法,線程從運行狀態(tài)進入就緒狀態(tài)
-
運行狀態(tài)轉(zhuǎn)阻塞狀態(tài):當(dāng)一個運行狀態(tài)的線程試圖獲取一個被其他線程持有的對象鎖時,該線程就會進入阻塞狀態(tài)。
synchronized(object) { // 如果此時object的鎖被其他線程持有,那么線程就從運行狀態(tài)進入阻塞狀態(tài) }
-
阻塞狀態(tài)轉(zhuǎn)就緒狀態(tài):當(dāng)一個阻塞狀態(tài)的線程獲取到了被其他線程釋放的對象鎖,該線程就由阻塞狀態(tài)變?yōu)榫途w狀態(tài),重新等待系統(tǒng)調(diào)度。
-
運行狀態(tài)轉(zhuǎn)等待狀態(tài):當(dāng)一個運行狀態(tài)的線程調(diào)用了
wait()
,join()
或LockSupport.park()
方法時,該線程就會進入等待狀態(tài)。等待狀態(tài)的線程需要依賴其他線程的通知才能夠返回到就緒狀態(tài)。t.wait(); // 調(diào)用wait()方法,線程從運行狀態(tài)進入等待狀態(tài) t.join(); // 調(diào)用join()方法,線程從運行狀態(tài)進入等待狀態(tài)
-
等待狀態(tài)轉(zhuǎn)就緒狀態(tài):當(dāng)一個等待狀態(tài)的線程被其他線程調(diào)用
notify()
或notifyAll()
喚醒,或者被其他線程中斷,或者等待的時間到期,該線程就由等待狀態(tài)轉(zhuǎn)為就緒狀態(tài)。t.notify(); // notify()方法被調(diào)用,線程從等待狀態(tài)進入就緒狀態(tài)
-
運行狀態(tài)轉(zhuǎn)超時等待狀態(tài):當(dāng)一個運行狀態(tài)的線程調(diào)用了具有超時參數(shù)的
sleep()
,wait()
,join()
,或LockSupport.parkNanos()
,LockSupport.parkUntil()
方法時,該線程就會進入超時等待狀態(tài)。Thread.sleep(1000); // 調(diào)用sleep()方法,線程從運行狀態(tài)進入超時等待狀態(tài)
-
超時等待狀態(tài)轉(zhuǎn)就緒狀態(tài):當(dāng)一個超時等待狀態(tài)的線程等待的時間到期,或者被其他線程喚醒或中斷,該線程就由超時等待狀態(tài)轉(zhuǎn)為就緒狀態(tài)。
-
任何狀態(tài)轉(zhuǎn)終止?fàn)顟B(tài):當(dāng)線程完成任務(wù)或者因異常退出時,就會進入終止?fàn)顟B(tài)。
通過了解以上線程的狀態(tài)轉(zhuǎn)換,可以更加深入理解線程的運行機制,為多線程編程提供理論基礎(chǔ)。
三、線程生命周期示例
下面的Java代碼實例演示了一個線程從創(chuàng)建到終止的整個過程:
// 創(chuàng)建一個繼承了Thread類的ExampleThread類
class ExampleThread extends Thread {
private Object lock; // 創(chuàng)建一個私有的Object對象,它將在同步代碼塊中被使用作為鎖
// 構(gòu)造函數(shù),接受一個Object類型的參數(shù)
public ExampleThread(Object lock) {
this.lock = lock; // 將傳入的對象賦值給lock
}
// 重寫Thread類的run方法
@Override
public void run() {
// 同步代碼塊,只有獲取到lock對象的鎖才能執(zhí)行
synchronized(lock) {
try {
// 輸出線程名和狀態(tài)
System.out.println(Thread.currentThread().getName() + " is running");
// 讓線程睡眠1秒,此時線程進入TIMED_WAITING狀態(tài)
Thread.sleep(1000);
// 輸出線程名和狀態(tài)
System.out.println(Thread.currentThread().getName() + " is waiting");
// 調(diào)用wait()方法,線程釋放lock鎖,進入WAITING狀態(tài)
lock.wait();
// 線程被喚醒,獲取到lock鎖,輸出線程名和狀態(tài)
System.out.println(Thread.currentThread().getName() + " is running again");
} catch (InterruptedException e) {
// 線程被中斷,輸出線程名和狀態(tài),然后線程將結(jié)束
System.out.println(Thread.currentThread().getName() + " is interrupted and will terminate");
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
// 創(chuàng)建一個共享的鎖對象
Object lock = new Object();
// 創(chuàng)建一個新的線程(NEW狀態(tài))
Thread t1 = new ExampleThread(lock);
System.out.println(t1.getName() + " is created");
// 啟動新的線程(READY/RUNNABLE狀態(tài))
t1.start();
// 讓主線程睡眠2秒,這樣新線程就可以先運行
Thread.sleep(2000);
// 喚醒等待的線程(將進入READY/RUNNABLE狀態(tài))
synchronized(lock) {
lock.notify();
}
// 讓主線程再睡眠1秒,這樣被喚醒的線程可以完成運行
Thread.sleep(1000);
}
}
這個代碼示例演示了Java線程從創(chuàng)建(NEW狀態(tài)),到就緒和運行(READY/RUNNABLE狀態(tài)),再到等待(WAITING狀態(tài)),被喚醒后再次運行,最后終止(TERMINATED狀態(tài))的整個過程。
以優(yōu)化應(yīng)用的性能。文章來源:http://www.zghlxwxcb.cn/news/detail-501216.html
結(jié)束語
希望以上內(nèi)容能幫助你理解Java線程的生命周期。理解線程生命周期對于編寫并發(fā)程序和進行多線程編程都十分重要。記住,最好的學(xué)習(xí)方法就是動手實踐。因此,我鼓勵大家自己動手嘗試上述代碼,更深入地理解線程生命周期的每個階段。文章來源地址http://www.zghlxwxcb.cn/news/detail-501216.html
到了這里,關(guān)于Java線程生命周期詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!