Java中的線程生命周期核心概念
前言:
在本文中,我們將詳細(xì)討論Java中的一個核心概念——線程的生命周期。我們將使用一個快速的圖解,當(dāng)然還有實用的代碼片段來更好地理解線程執(zhí)行期間的這些狀態(tài)。
Java多線程
在Java語言中,多線程是由線程的核心概念驅(qū)動的。線程在其生命周期中會經(jīng)歷各種狀態(tài):
Java中線程的生命周期
java.lang.Thread
類包含一個靜態(tài)枚舉,它定義了它的潛在狀態(tài)。在任何給定的時間點內(nèi),線程只能處于以下狀態(tài)之一:
- NEW – 一個新創(chuàng)建的線程,尚未開始執(zhí)行
- RUNNABLE – 正在運行或準(zhǔn)備執(zhí)行,但它正在等待資源分配
- BLOCKED – 等待獲取監(jiān)視器鎖以進(jìn)入或重新進(jìn)入同步塊/方法
- WAITING – 等待其他線程執(zhí)行特定操作,無任何時間限制
- TIMED_WAITING – 等待其他線程在指定時間段內(nèi)執(zhí)行特定操作
- TERMINATED – 已完成執(zhí)行
上圖涵蓋了所有這些狀態(tài);現(xiàn)在讓我們詳細(xì)討論其中的每一項。
NEW
新線程(或出生線程)是已創(chuàng)建但尚未啟動的線程。在我們使用start()
方法啟動它之前,它一直保持此狀態(tài)。
以下代碼段顯示了新創(chuàng)建的處于新狀態(tài)的線程:
Runnable runnable = new NewState(); Thread t = new Thread(runnable); Log.info(t.getState());
由于我們尚未啟動上述線程,因此方法t.getState()
會打?。?/p>
NEW
Runnable
當(dāng)我們創(chuàng)建了一個新線程并對其調(diào)用start()
方法時,它將從NEW
狀態(tài)移動到RUNNABLE
狀態(tài)。處于此狀態(tài)的線程正在運行或準(zhǔn)備運行,但它們正在等待來自系統(tǒng)的資源分配。
在多線程環(huán)境中,線程調(diào)度程序(JVM的一部分)為每個線程分配固定的時間量。因此,它會運行一段特定的時間,然后將控制權(quán)交給其他可運行的線程。
例如,讓我們將t.start()
方法添加到前面的代碼中,并嘗試訪問其當(dāng)前狀態(tài):
Runnable runnable = new NewState(); Thread t = new Thread(runnable); t.start(); Log.info(t.getState());
此代碼很可能返回以下輸出:
RUNNABLE
請注意:在本例中,并不總是保證在控件到達(dá)t.getState()時,它仍處于可運行狀態(tài)。
線程調(diào)度器可能會立即對其進(jìn)行調(diào)度,并可能完成執(zhí)行。在這種情況下,我們可能會得到不同的輸出。
Blocked
當(dāng)前沒有資格運行的線程處于阻塞狀態(tài)。它在等待監(jiān)視器鎖定并嘗試訪問被其他線程鎖定的代碼段時進(jìn)入此狀態(tài)。
讓我們嘗試重現(xiàn)這種狀態(tài):
public class BlockedState { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new DemoThreadB()); Thread t2 = new Thread(new DemoThreadB()); t1.start(); t2.start(); Thread.sleep(1000); Log.info(t2.getState()); System.exit(0); } } class DemoThreadB implements Runnable { @Override public void run() { commonResource(); } public static synchronized void commonResource() { while(true) { // Infinite loop to mimic heavy processing // 't1' won't leave this method // when 't2' try to enter this } } }
在此代碼中:
- 我們創(chuàng)建了兩個不同的線程—
t1
和t2
t1
啟動并進(jìn)入synchronized commonResource()
方法;這意味著只有一個線程可以訪問它;在當(dāng)前線程完成處理之前,將阻止嘗試訪問此方法的所有其他后續(xù)線程進(jìn)一步執(zhí)行- 當(dāng)
t1
進(jìn)入此方法時,它將保持在無限while
循環(huán)中;這只是為了模擬繁重的處理,以便所有其他線程都無法進(jìn)入此方法 - 現(xiàn)在,當(dāng)我們啟動t2時,它嘗試進(jìn)入
commonResource()
方法,t1
已經(jīng)訪問了該方法,因此t2
將保持在阻塞狀態(tài)
處于這種狀態(tài),我們稱之為t2.getState()
并獲取輸出,如下所示:
BLOCKED
Waiting
線程在等待其他線程執(zhí)行特定操作時處于等待狀態(tài)。
根據(jù)JavaDocs,任何線程都可以通過調(diào)用以下三種方法中的任何一種進(jìn)入這種狀態(tài):
object.wait()
thread.join()
LockSupport.park()
請注意,在wait()
和join()
中,我們沒有定義任何超時時間,因為下一節(jié)將介紹該場景。
現(xiàn)在,讓我們嘗試重現(xiàn)這種狀態(tài):
public class WaitingState implements Runnable { public static Thread t1; public static void main(String[] args) { t1 = new Thread(new WaitingState()); t1.start(); } public void run() { Thread t2 = new Thread(new DemoThreadWS()); t2.start(); try { t2.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.error("Thread interrupted", e); } } } class DemoThreadWS implements Runnable { public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.error("Thread interrupted", e); } Log.info(WaitingState.t1.getState()); } }
讓我們討論一下我們在這里做什么:
- 我們已經(jīng)創(chuàng)建并啟動了
t1
t1
創(chuàng)建t2
并啟動它- 當(dāng)
t2
的處理繼續(xù)時,我們稱之為t2.join()
,這會使t1
處于等待狀態(tài),直到t2
完成執(zhí)行 - 因為
t1
正在等待t2
完成,所以我們調(diào)用t1.getState()
來自t2
正如您所期望的那樣,這里的輸出是:
WAITING
Timed Waiting
當(dāng)線程等待另一個線程在規(guī)定的時間內(nèi)執(zhí)行特定操作時,該線程處于TIMED_WAITING
狀態(tài)。
根據(jù)JavaDocs,有五種方法可以將線程置于TIMED_WAITING
狀態(tài):
thread.sleep(long millis)
wait(int timeout)
或wait(int timeout, int nanos)
thread.join(long millis)
LockSupport.parkNanos
LockSupport.parkUntil
現(xiàn)在,讓我們嘗試快速重現(xiàn)這種狀態(tài):
public class TimedWaitingState { public static void main(String[] args) throws InterruptedException { DemoThread obj1 = new DemoThread(); Thread t1 = new Thread(obj1); t1.start(); // The following sleep will give enough time for ThreadScheduler // to start processing of thread t1 Thread.sleep(1000); Log.info(t1.getState()); } } class DemoThread implements Runnable { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.error("Thread interrupted", e); } } }
這里,我們創(chuàng)建并啟動了一個線程t1
,該線程進(jìn)入睡眠狀態(tài),超時時間為5秒;
輸出將為:
TIMED_WAITING
Terminated
這是死線程的狀態(tài)。當(dāng)它完成執(zhí)行或異常終止時,它處于終止?fàn)顟B(tài)。
讓我們在以下示例中嘗試實現(xiàn)此狀態(tài):
public class TerminatedState implements Runnable { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new TerminatedState()); t1.start(); // The following sleep method will give enough time for // thread t1 to complete Thread.sleep(1000); Log.info(t1.getState()); } @Override public void run() { // No processing in this block } }
在這里,雖然我們已經(jīng)啟動了線程t1
,但它是下一個語句Thread.sleep(1000)
為t1提供了足夠的時間來完成,因此該程序為我們提供如下輸出:
TERMINATED
除了線程狀態(tài)之外,我們還可以檢查isAlive()
方法以確定線程是否處于活動狀態(tài)。例如,如果我們在此線程上調(diào)用isAlive()
方法:
Assert.assertFalse(t1.isAlive());
結(jié)論
在本文中,我們學(xué)習(xí)了Java中線程的生命周期。我們查看了線程定義的所有六個狀態(tài)。陳述enum并用快速示例再現(xiàn)它們。雖然代碼片段在幾乎每臺機(jī)器上都會給出相同的輸出,但在某些例外情況下,我們可能會得到一些不同的輸出,因為無法確定線程調(diào)度器的確切行為。
到此這篇關(guān)于Java中的線程生命周期核心概念的文章就介紹到這了,更多相關(guān)Java線程生命周期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用spring的websocket創(chuàng)建通信服務(wù)的示例代碼
這篇文章主要介紹了使用spring的websocket創(chuàng)建通信服務(wù)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11Springboot多環(huán)境開發(fā)及使用方法
這篇文章主要介紹了Springboot多環(huán)境開發(fā)及多環(huán)境設(shè)置使用、多環(huán)境分組管理的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03詳解Java多線程編程中互斥鎖ReentrantLock類的用法
Java多線程并發(fā)的程序中使用互斥鎖有synchronized和ReentrantLock兩種方式,這里我們來詳解Java多線程編程中互斥鎖ReentrantLock類的用法:2016-07-07