java多線程學習(三)——線程棧

一、線程棧模型

線程棧模型是理解線程調度原理以及線程執行過程的基礎。線程棧是指某時刻時內存中線程調度的棧信息,當前調用的方法總是位於棧頂,線程棧的內容是隨着線程的運行狀態變化而變化的,研究線程棧必須選擇一個運行的時刻(指代碼運行到什麼地方)


上圖中的棧A是主線程main的運行棧信息,當執行new JavaThreadDemo().threadMethod();方法時,threadMethod方法位於主線程棧中的棧頂,在threadMethod方法中運行的start()方法新建立了一個線程,此時,新建立的線程也將擁有自己的線程棧B,可以看到在不同運行時刻棧的信息在發生變化,棧A的變化可以從上圖中看出來。此時棧A和棧B並行運行,main線程和新建立的線程並行運行。由此可以看出方法調用和線程啓動的區別。方法調用只是在原來的線程棧中調用方法的代碼,而線程啓動會新建立一個獨屬於自己的線程棧來運行自己的這個線程。

二、線程的生命週期

線程的生命週期包括五種狀態:新建、可運行狀態、運行狀態、阻塞、死亡。


新建:創建了一個新的線程對象,但是還沒有調用線程中start()方法,此時線程處於新建狀態。

可運行狀態:調用線程的start()方法,線程進入可運行狀態,此時線程等待着JVM的調度程序來執行,就是說我已經準備好了,可以上戰場了,只等待一個機會就可以變爲運行狀態了。

運行狀態:線程調度程序從衆多的可運行狀態線程中選擇一個線程來運行,好比主帥選擇一個大將來上陣較量。這也是線程進入運行狀態的唯一方式,必須由JVM來調度。

阻塞狀態:線程的等待、睡眠和阻塞統稱爲阻塞狀態,此時線程依然是活得,處於待命狀態,知道某個條件出現時,即可返回可運行狀態。

死亡狀態:當線程的run()方法執行完畢後,線程即結束。此時線程已經不在存在,它所佔用的所有資源都會被回收。


三、線程阻塞

線程的阻塞有多種,常見的包括三項(IO阻塞不討論)

1、睡眠

2、等待

3、獲取線程鎖而阻塞

睡眠狀態:線程的sleep()方法可以使一個正在執行的線程進入睡眠狀態。線程睡眠時,不會返回可運行狀態,當睡眠時間到時才返回可運行狀態。

@Override
	public void run() {
		for(int i = 0; i < 5; i++) {
			try {
				Thread.sleep(50);//模擬耗時操作
				System.out.println(name + ":" + i);
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
調用線程的靜態方法Thread.sleep()可以使線程睡眠,參數爲毫秒。

1、線程處於睡眠狀態時,JVM調度程序會暫停此線程的執行並來執行其他的處於可運行狀態的線程。

2、sleep()方法是Thread的靜態方法,只能控制當前線程的睡眠。

3、線程睡眠時間到之後會返回到可運行狀態,而不是運行狀態。

線程的優先級和線程讓步yield()

線程通過調用Thread.yield()方法來實現線程的讓步。yield()方法的作用爲暫停當前正在執行的線程對象,讓出處理器資源,讓處理器來執行其他線程。

Java中的線程存在優先級,優先級的範圍爲1——10,之間。JVM的線程調度程序是基於優先級的搶先調度機制。高優先級的線程比低優先級的線程有更高的機率得到執行,只是機率高一點,並不是說低優先級的線程必須等待高優先級的線程執行完成後纔開始執行,只是得到的資源分配的比例不一樣而已。(線程優先級在實際應用中並不能按你預期的來執行)

當線程池中的線程都具有相同的優先級時,JVM的調度程序隨機選擇處於可運行狀態的線程來執行,此時可能有兩種執行過程:(1)選擇一個線程運行,直到此線程阻塞或者運行到死亡。(2)時間分片機制,爲線程池中的每個線程都提供均勻的運行機會。

設置線程的優先級可以通過調用線程的setPriority(int)方法來設置線程的優先級。默認的線程優先級爲5,JVM不會隨便更改一個線程的優先級,但是不同系統中的線程優先級的範圍可能不同,當JVM不能識別10個不同的優先級時,JVM會將這些優先級進行兩個或者多個的合併,此時合併前的不同優先級的線程最後會被合併成一個優先級的線程。

Thread類中定義了三個常量來定義優先級的範圍:

static int MAX_PRIORITY 線程具有的最大優先級

static int MIN_PRIORITY  線程具有的最小優先級

static int NORM_PRIORITY 線程具有的默認優先級


使線程讓步的yield()方法

Thread.yield()方法可以暫停當前正在執行的線程,使處理器來有機會執行其他線程,即可以讓當前線程做出讓步,也讓其他線程有機會被執行。線程執行yield()方法後,線程就從運行狀態回到了可運行狀態,使具有相同優先級的線程獲得機會來執行。使用yield()方法可以做到在相同優先級的線程之間適當的輪換執行。但是,實際中無法保證yield()方法達到讓步,因爲讓步的線程從運行狀態回到了可運行狀態,那麼此線程還可以被JVM的調度機制來選中來執行。


join方法

Thread的非靜態方法join()讓一個線程B加入到另一個線程A的尾部,直到線程A執行完畢後,線程B才能繼續執行。這相當於打斷線程B的執行來先執行了線程A,類似與在main()函數中調用了另一個函數,直到此函數執行完畢後,main()函數才繼續執行。

join的方法中有一個帶時間參數的版本,t.join(5000)讓線程等待5000毫秒,如果超過這個時間,則停止等待,變爲可運行狀態。


讓線程暫時離開運行狀態的三中方法:

1、調用線程的sleep()方法,使線程睡眠一段時間

2、調用線程的yield()方法,使線程暫時回到可運行狀態,來使其他線程有機會執行。

3、調用線程的join()方法,使當前線程停止執行,知道當前線程中加入的線程執行完畢後,當前線程纔可以執行。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章