1. 程式人生 > 其它 >Java 執行緒的五種狀態 與 建立執行緒

Java 執行緒的五種狀態 與 建立執行緒

Java 執行緒的 5 種狀態

執行緒狀態圖:

執行緒共包含以下五種狀態:
1、新建狀態(New)執行緒物件被建立後,就進入了新建狀態,例如,Thread thread = new Thread();

2、就緒狀態(Runnable):也稱之為“可執行”狀態。執行緒物件被建立後,其它執行緒呼叫該物件的start()方法,從而啟動該執行緒。例如:thread.start()。處於就緒狀態的執行緒,隨時可能被CPU排程執行。

3、執行狀態(Running)執行緒獲取CPU許可權進行執行。需要注意的是,執行緒只能從就緒狀態進入到執行狀態。如果在給定的時間片內沒有執行完成,就會被系統換下來等待下一次的執行。

4、阻塞狀態(Blocked)阻塞狀態是執行緒因為某種原因讓出CPU並暫時停止執行,進入阻塞狀態。在阻塞狀態的執行緒不能直接進入就緒狀態,只有當引起阻塞的原因消除時,執行緒才轉入到就緒狀態,然後重新到就緒佇列中排隊等待,被系統選中後從原來停止的位置開始繼續執行。

阻塞的情況分三種

  • (1)等待阻塞:通過呼叫執行緒的wait()方法,讓執行緒等待某工作的完成;
  • (2)同步阻塞:執行緒在獲取synchronized同步鎖失敗(因為鎖被其它執行緒所佔用),它會進入同步阻塞狀態;
  • (3)其他阻塞:通過呼叫執行緒的sleep()或join()或發出了I/O請求時,執行緒會進入到阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或超時、或者I/O處理完畢,執行緒重新轉入到就緒狀態。

5、死亡狀態(Dead):死亡狀態是執行緒生命週期中最後一個階段。執行緒死亡的原因有三個,一是正常執行的執行緒執行完成;二是執行緒丟擲未捕獲的異常;三是執行緒被強制終止,如呼叫stop()方法來終止一個執行緒【不推薦使用】。並且已死亡的執行緒不可以使用start()復活。

獲取執行緒基本資訊的方法

1、static Thread currentThread() 返回目前正在執行的執行緒
2、final String getName() 返回執行緒的名稱
3、final boolean isAlive() 判斷執行緒是否處於活動狀態
4、final int getPriority() 獲取執行緒的優先順序
5、final void setPriority(int priority)

設定執行緒的優先順序

Java建立執行緒

Java使用Thread類代表執行緒,所有的執行緒物件都必須是Thread類或其子類的物件。

1、繼承Thread類

  • (1)定義Thread類的子類,並重寫run()方法。run()方法的方法體就代表了執行緒需要完成的任務,因此把run()方法稱為執行緒執行體;
  • (2)建立Thread子類的例項,即建立了執行緒物件
  • (3)呼叫執行緒物件的start()方法來啟動執行緒
  • 注意:使用繼承Thread類的方法來建立執行緒類時,多個執行緒之間無法共享執行緒類的例項變數。

2、實現Runnable介面

  • (1)定義Runnable介面的實現類,並重寫該介面的run()方法,該run()方法的方法體同樣是該執行緒的執行緒執行體;
  • (2)建立Runnable實現類的例項,並以此例項作為Thread的target來建立Thread物件,該Thread物件才是真正的執行緒物件;
  • (3)呼叫執行緒物件的start()方法來啟動該執行緒;
  • 注意:實際的執行緒物件依然是該Thread例項,只是該Thread例項負責執行其target的run()方法
  • 注意:採用Runnable介面的方式建立的多個執行緒可以共享執行緒類的例項變數,這是因為在這種方式下,程式所建立的Runnable物件只是執行緒的target,而多個執行緒可以共享同一個target所以多個執行緒可以共享同一個執行緒類(實際上是執行緒的target類)的例項變數

3、使用Callable和Future建立執行緒

前言:C#可以把任意方法包裝成執行緒執行體,包括有返回值的方法;但Java不可以把任意方法都包裝成執行緒執行體。從Java 5開始,Java提供了Callable介面,該方法提供了一個call()方法可以作為執行緒執行體,call()方法可以有返回值,可以宣告丟擲異常。Java 5提供Future介面來代表Callable接口裡call()方法的返回值,併為Future介面提供了一個FutureTask實現類,該實現類實現了Future介面,並實現了Runnable介面 ==》 可以作為Thread類的target。

  • 1、建立Callable介面的實現類,並實現call()方法,該call()方法將作為執行緒執行體,且該call()方法有返回值,再建立Callable實現類的例項。
  • 2、使用FutureTask類來包裝Callable物件,該FutureTask物件封裝了該Callable物件的call()方法的返回值
  • 3、建立並呼叫FutureTask物件作為Thread物件的target,建立並啟動新執行緒
  • 4、呼叫FutureTask物件的get()方法來獲得子執行緒執行結束後的返回值
//先使用lamdba表示式建立Callable<Integer>物件
//使用FutureTask來包裝Callable物件
FutureTask<Integer> task = new FutureTask<<>((Callable<Integer>)()->{
    var i=1;
    System.out.println(Thread.currentThread().getName()+"變數i="+i);
    //call()方法可以有返回值
    return i+1;
});
//實質還是以Callable物件來建立並啟動執行緒
new Thread(task,"有返回值的執行緒").start();
try{
    //獲取執行緒返回值
    System.out.println("子執行緒的返回值:"+task.get());
}catch(Exception e){
    e.printStackTrace();
}

注意:Callable介面有泛型限制,Callable接口裡的泛型形參型別與call()方法返回值型別相同,且Callable介面是函式式介面,因此使用Lambda表示式來建立Callable物件。