Java 多線程詳解(五)------線程的聲明周期


這篇博客介紹線程的生命周期。

  線程是一個動態執行的過程,它也有從創建到死亡的過程。

在 Thread 類中,有一個枚舉內部類:

  

 

 

上面的信息以圖片表示如下:

  第一張圖:

  

 

  第二張圖:把等待、計時等待、阻塞看成阻塞一個狀態了

  

 

1、新建狀態(new):使用 new 創建一個線程,僅僅只是在堆中分配了內存空間

           新建狀態下,線程還沒有調用 start()方法啟動,只是存在一個線程對象而已

          Thread t = new Thread();//這就是t線程的新建狀態

 

 

2、可運行狀態(runnable):新建狀態調用 start() 方法,進入可運行狀態。而這個又分成兩種狀態,ready 和 running,分別表示就緒狀態和運行狀態

    就緒狀態:線程對象調用了 start() 方法,等待 JVM 的調度,(此時該線程並沒有運行)

    運行狀態:線程對象獲得 JVM 調度,如果存在多個 CPU,那么運行多個線程並行運行

  注意:線程對象只能調用一次 start() 方法,否則報錯:illegaThreadStateExecptiong

 

3、阻塞狀態(blocked):正在運行的線程因為某種原因放棄 CPU,暫時停止運行,就會進入阻塞狀態。此時 JVM 不會給線程分配 CPU,知道線程重新進入就緒狀態,才有機會轉到 運行狀態。

  注意:阻塞狀態只能先進入就緒狀態,不能直接進入運行狀態

  阻塞狀態分為兩種情況:

    ①、當線程 A 處於可運行狀態中,試圖獲取同步鎖時,卻被 B 線程獲取,此時 JVM 把當前 A 線程放入鎖池中,A線程進入阻塞狀態

    ②、當線程處於運行狀態時,發出了 IO 請求,此時進入阻塞狀態

 

 

4、等待狀態(waiting):等待狀態只能被其他線程喚醒,此時使用的是無參數的 wait() 方法

  ①、當線程處於運行狀態時,調用了 wait() 方法,此時 JVM 把該線程放入等待池中

 

5、計時等待(timed waiting):調用了帶參數的 wait(long time)或 sleep(long time) 方法

  ①、當線程處於運行狀態時,調用了帶參數 wait 方法,此時 JVM 把該線程放入等待池中

  ②、當前線程調用了 sleep(long time) 方法

 

 

6、終止狀態(terminated):通常稱為死亡狀態,表示線程終止

  ①、正常終止,執行完 run() 方法,正常結束

  ②、強制終止,如調用 stop() 方法或 destory() 方法

  ③、異常終止,執行過程中發生異常

 

 

下面詳細介紹線程的幾種方法:

  1、sleep(long millis)線程休眠:讓執行的線程暫停一段時間,進入計時等待狀態。

    static void sleep(long millis):調用此方法后,當前線程放棄 CPU 資源,在指定的時間內,sleep 所在的線程不會獲得可運行的機會,此狀態下的線程不會釋放同步鎖(注意和 wait() 的區別,wait 會放棄 CPU 資源,同時也會放棄 同步鎖)

    該方法更多的是用來模擬網絡延遲,讓多線程並發訪問同一資源時的錯誤效果更加明顯。

 

   2、join()聯合線程:表示這個線程等待另一個線程完成后(死亡)才執行,join 方法被調用之后,線程對象處於阻塞狀態。寫在哪個線程中,哪個線程阻塞

    這種也稱為聯合線程,就是說把當前線程和當前線程所在的線程聯合成一個線程

    

package com.ys.thread;

class Join extends Thread{
	@Override
	public void run() {
		for(int i = 0 ; i < 10 ;i++){
			System.out.println("播放音樂"+i);
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		//創建 join 線程對象
		Join joinThread = new Join();
		for(int i = 0 ; i < 10 ; i++){
			System.out.println("玩游戲"+i);
			if(i==3){
				joinThread.start();
			}
			if(i==5){
				try {
					joinThread.join();//強制運行 join 線程,知道 join 運行完畢了,main 才有機會運行
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

  結果:

玩游戲0
玩游戲1
玩游戲2
玩游戲3
玩游戲4
玩游戲5
播放音樂0
播放音樂1
播放音樂2
播放音樂3
播放音樂4
播放音樂5
播放音樂6
播放音樂7
播放音樂8
播放音樂9
玩游戲6
玩游戲7
玩游戲8
玩游戲9

  

 

 

后台線程(守護線程):在后台運行的線程,其目的是為其他線程提供服務,也稱為“守護線程”。

①、JVM 的垃圾回收線程就是守護線程。

②、main 方法是前台線程,不是后台線程

  

public static void main(String[] args) {
		String mainThreadName = Thread.currentThread().getName();
		System.out.println(mainThreadName);  //main
		
		System.out.println(Thread.currentThread().isDaemon());//false
		
	}

  

特點:

①、若所有的前台線程都死亡,則后台線程自動死亡;

②、前台線程沒有結束,后台線程是不會結束的;

③、前台線程創建的線程是前台線程,后台線程創建的線程是后台線程。

  Thread.setDaemon(Boolean on)必須在 start() 的方法前調用。否則會報錯。

 

 

 

 

線程的優先級:

  每個線程都有一個優先級,這有助於 系統確定線程的調動順序。

  Java 線程的優先級是一個整數,取值范圍是:1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )

  默認情況下,每一個線程都會分配一個優先級 NORM_PRIORITY(5)。

  具有較高優先級的線程對程序更重要,並且應該在低優先級的線程之前分配處理器資源。但是,線程優先級不能保證線程執行的順序,而且非常依賴於平台。

 

 

 

 

線程禮讓:

yield()方法:表示當前線程對象提示調度器自己願意讓出 CPU 資源,但是調度器可以自由的忽略該提示。

       調用該方法后,線程對象進入就緒狀態,所以完全有可能:某個線程調用了 yield() 方法,但是線程調度器又把它調度出來重新執行。

從 Java7 提供的文檔上可以清楚的看出,開發中會很少使用該方法,該方法主要運用於調試或測試,它可能有助於多線程競爭條件下的錯誤重現現象。

 

sleep() 和 yield() 方法的區別:

  ①、都能使當前處於運行狀態的線程放棄 CPU資源,把運行的機會給其他線程

  ②、sleep 方法會給其他線程運行的機會,但是不考慮其他線程優先級的問題;yield 方法會優先給更高優先級的線程運行機會

  ③、調用 sleep 方法后,線程進入計時等待狀態,調用 yield 方法后,線程進入就緒狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM