05-執行緒的狀態以及各狀態之間的轉換詳解
執行緒被創建出來之後,它並不是會立刻執行,而是由多個執行緒進行搶佔CPU資源,那麼,哪一個執行緒搶佔到了,那一個執行緒就來執行。就像之前講的烤燒餅的例子一樣,爐子上面有多個任務在轉,轉到哪個任務(燒餅),那麼,那個任務就執行,也就是說,在這個過程中,涉及到執行緒的生命週期的問題,就是說,從執行緒的建立到執行緒的結束的這個過程,它所經歷的各個階段,即執行緒的狀態
那麼,可以說,執行緒從建立到死亡,可以說有七個狀態,首先第一個我們把它稱之為例項化,也就是所謂的初始化狀態,那麼,初始化狀態呼叫了start()方法,start()方法是啟動一個執行緒,那麼就變成了ready to run,ready to run並不是run,而是一個準備執行狀態,它也是屬於就緒狀態,由就緒狀態我們發現,如果此時它搶到了CPU資源,就變成了執行狀態,就是執行中狀態(Running),那麼,當它執行完畢之後,正常的就結束了,那麼就到了Dead,也就是所謂的終止階段,死亡階段,說明這個過程就正常結束了,這就是一個完整的生命週期,但是,在這個過程中,我們知道,就像人的一生一樣,總會遇到很多的磨難,比如說,在準備就緒的階段,突然遇到了stop,於是就死了。當正處於執行狀態的時候,突然呼叫sleep方法,於是就睡覺了,或者當正處於執行狀態的時候,突然呼叫wait方法,於是就到了等待狀態,或者當正處於執行狀態的時候,遇到了IO的阻塞或進入到一個同步程式碼塊,於是在外面等待。
Blocked就是阻塞狀態。
Sleeping和Waiting這兩個狀態我們可以怎麼理解呢?Sleeping其實也是一種等待,它是一種超時等待,這個超時等待就是說,當一定時間過了之後,它就能自己再回到ready to run狀態去競爭CPU資源。而Waiting,我們就認為它是一個等待狀態,那麼,如果沒有人喚醒它,它將一直等待下去,必須要有人通過notify()或者notifyAll()來進行喚醒(上圖中這裡寫的不對,)就是說,超時等待這一塊,你可以設定超時等待的時間,那麼,等它的時間到了之後,它就會自動的去進入到ready to run(就緒狀態)去競爭CPU的資源。
阻塞狀態就是說,當資料獲取到了它就不再阻塞到IO上了,於是就進入了Running(執行狀態),或者就是說Lock obtained,就是說拿到這個鎖之後,它也就不再進行阻塞了,當然了,在阻塞過程中也有可能會直接進入Dead(終止狀態)。
由Waiting(等待狀態)或者Sleeping(超時等待狀態)是不會直接進入到Dead(終止狀態的)。只可能從執行狀態進入到等待狀態或者超時等待狀態,從等待狀態和超時等待狀態只能回到就緒狀態。
這就是整個執行緒的整個生命週期。
下面我們就通過程式碼來演示一下執行緒的整個生命週期。
這就是所謂的初始化狀態,也就是被new出來的時候就是一個初始化狀態,等我們呼叫start()方法之後,就變成了ready to run,而並不是Running,那麼,怎麼來驗證它是ready to run而不是Running呢?我們說,如果建立了多個執行緒,那麼就會有多個處於就緒狀態,它們同時去爭奪CPU資源,那麼,誰搶到了那麼誰就變成了Running,誰沒有搶到,那麼它依然就處於ready to run,那麼,也就是說,當我們的CPU是單核的時候,那麼,如果有多個執行緒,那麼就會多個執行緒同時搶用這一個CPU資源,那麼,也就是說,是有一部分執行緒處於等待。
所以就是說,當你呼叫了start()方法之後,它只是處於就緒狀態,它就去競爭CPU資源,那麼,如果搶到了CPU資源,就變成Running,那麼,如果沒有搶到,那麼,依然處於就緒狀態,那麼,當搶到了CPU資源,在進行Running的時候,它也有可能會被就緒狀態的執行緒去搶佔CPU資源,所以說,我們發現並不是一個執行緒搶佔了CPU資源之後就一隻執行,而是過了一會又被其他執行緒給搶佔了,就是這麼一個情況。
當執行緒走到Thread.sleep(100);這段程式碼的時候,當前的這個執行緒就會處於sleeping狀態,也就是超時等待狀態,那麼,當等待時間結束了之後,接著進入到就緒狀態,去搶佔CPU資源。
發現Thread中沒有wait()方法,也就是說wait()並不是Thread類的靜態方法,它是物件的方法,我們知道,所有類的父類是Object類。等待就是呼叫物件的wait()方法。呼叫了wait()方法之後,它會一直處於等待狀態,那麼,直到呼叫了notify或者notifyAll之後,它才會處於就緒狀態。
我們就用程式碼簡單的測試一下。
我們需要兩個執行緒。
這個地方報錯了,這個地方後面會詳細的講。呼叫了wait()和notify()方法,它其實是必須要跟一個同步監視器的,而且這個同步監視器所指定的物件必須是當前類的例項,
我們發現一個是等待,一個是喚醒。當處於wait狀態的時候它就一直等待,當有了等待之後,那麼,當主執行緒執行到notify()或者notifyAll()之後,wait狀態的執行緒就被喚醒了,於是它處於就緒狀態,開始搶奪CPU資源,如果搶到CPU資源,那麼就開始執行,本例中執行完之後又處於wait狀態,然後接著主執行緒執行。
這就是關於wait和notify的關係。後面我們會詳細的給大家講解這個問題。這裡僅僅是給大家來演示執行緒的狀態。到後面執行緒之間的通訊這些問題會詳細的講。
關於執行緒之間的狀態就說到這裡。