Java併發程式設計 執行緒的狀態和執行緒的建立

2021-09-10 19:07:02 字數 2840 閱讀 3122

執行緒的狀態

新建狀態(new):新建立了乙個執行緒物件。

就緒狀態(runnable):執行緒物件建立後,其他執行緒呼叫了該物件的start()方法。該狀態的執行緒位於「可執行執行緒池」中,變得可執行,只等待獲取cpu的使用權。即在就緒狀態的程序除cpu之外,其它的執行所需資源都已全部獲得。

執行狀態(running):就緒狀態的執行緒獲取了cpu,執行程式**。

阻塞狀態(blocked):阻塞狀態是執行緒因為某種原因放棄cpu使用權,暫時停止執行。直到執行緒進入就緒狀態,才有機會轉到執行狀態。

阻塞的情況分三種:

死亡狀態(dead):執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。

執行緒的初始化、中斷

建立執行緒的多種方式,執行緒就進入了初始狀態

當該物件呼叫了start()方法,就進入就緒狀態;

進入就緒後,當該物件被作業系統選中,獲得cpu時間片就會進入執行狀態;

進入執行狀態後情況就比較複雜了

run()方法或main()方法結束後,執行緒就進入終止狀態;

2.當執行緒呼叫了自身的sleep()方法或其他執行緒的join()方法,程序讓出cpu,然後就會進入阻塞狀態(該狀態既停止當前執行緒,但並不釋放所占有的資源即呼叫sleep ()函式後,執行緒不會釋放它的「鎖標誌」。)。當sleep()結束或join()結束後,該執行緒進入可執行狀態,繼續等待os分配cpu時間片。典型地,sleep()被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓執行緒阻塞一段時間後重新測試,直到條件滿足為止。

執行緒呼叫了yield()方法,意思是放棄當前獲得的cpu時間片,回到就緒狀態,這時與其他程序處於同等競爭狀態,os有可能會接著又讓這個程序進入執行狀態; 呼叫 yield() 的效果等價於排程程式認為該執行緒已執行了足夠的時間片從而需要轉到另乙個執行緒。yield()只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行。

當執行緒剛進入可執行狀態(注意,還沒執行),發現將要呼叫的資源被synchroniza(同步),獲取不到鎖標記,將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池裡也許已經有了其他執行緒在等待獲取鎖標記,這時它們處於佇列狀態,既先到先得),一旦執行緒獲得鎖標記後,就轉入就緒狀態,等待os分配cpu時間片;

suspend() 和 resume()方法:兩個方法配套使用,suspend()使得執行緒進入阻塞狀態,並且不會自動恢復,必須其對應的resume()被呼叫,才能使得執行緒重新進入可執行狀態。典型地,suspend()和 resume() 被用在等待另乙個執行緒產生的結果的情形:測試發現結果還沒有產生後,讓執行緒阻塞,另乙個執行緒產生了結果後,呼叫 resume()使其恢復。

wait()和 notify() 方法:當執行緒呼叫wait()方法後會進入等待佇列(進入這個狀態會釋放所占有的所有資源,與阻塞狀態不同),進入這個狀態後,是不能自動喚醒的,必須依靠其他執行緒呼叫notify()或notifyall()方法才能被喚醒(由於notify()只是喚醒乙個執行緒,但我們由不能確定具體喚醒的是哪乙個執行緒,也許我們需要喚醒的執行緒不能夠被喚醒,因此在實際使用時,一般都用notifyall()方法,喚醒有所執行緒),執行緒被喚醒後會進入鎖池,等待獲取鎖標記。

wait() 使得執行緒進入阻塞狀態,它有兩種形式:

上述的核心區別導致了一系列的細節上的區別

首先,前面敘述的所有方法都隸屬於 thread類,但是wait() 和 notify() 方法這一對卻直接隸屬於 object 類,也就是說,所有物件都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放占用的鎖,而鎖是任何物件都具有的,呼叫任意物件的 wait() 方法導致執行緒阻塞,並且該物件上的鎖被釋放。而呼叫任意物件的notify()方法則導致因呼叫該物件的 wait()方法而阻塞的執行緒中隨機選擇的乙個解除阻塞(但要等到獲得鎖後才真正可執行)。

其次,前面敘述的所有方法都可在任何位置呼叫,但是wait() 和 notify() 方法這一對方法卻必須在 synchronized 方法或塊中呼叫,理由也很簡單,只有在synchronized方法或塊中當前執行緒才占有鎖,才有鎖可以釋放。同樣的道理,呼叫這一對方法的物件上的鎖必須為當前執行緒所擁有,這樣才有鎖可以釋放。因此,這一對方法呼叫必須放置在這樣的 synchronized方法或塊中,該方法或塊的上鎖物件就是呼叫這一對方法的物件。若不滿足這一條件,則程式雖然仍能編譯,但在執行時會出現illegalmonitorstateexception異常。

wait() 和 notify()方法的上述特性決定了它們經常和synchronized方法或塊一起使用,將它們和作業系統的程序間通訊機制作乙個比較就會發現它們的相似性:synchronized方法或塊提供了類似於作業系統原語的功能,它們的執行不會受到多執行緒機制的干擾,而這一對方法則相當於 block和wake up 原語(這一對方法均宣告為 synchronized)。它們的結合使得我們可以實現作業系統上一系列精妙的程序間通訊的演算法(如訊號量演算法),並用於解決各種複雜的執行緒間通訊問題。

關於 wait() 和 notify() 方法最後再說明兩點:

第一:呼叫notify() 方法導致解除阻塞的執行緒是從因呼叫該物件的 wait()方法而阻塞的執行緒中隨機選取的,我們無法預料哪乙個執行緒將會被選擇,所以程式設計時要特別小心,避免因這種不確定性而產生問題。

第二:除了notify(),還有乙個方法 notifyall()也可起到類似作用,唯一的區別在於,呼叫 notifyall()方法將把因呼叫該物件的 wait()方法而阻塞的所有執行緒一次性全部解除阻塞。當然,只有獲得鎖的那乙個執行緒才能進入可執行狀態。

多執行緒的風險

飢餓與公平

如何避免飢餓問題

參考:執行緒的幾種狀態轉換

Java併發程式設計 執行緒的基本狀態

執行緒基本上有5種狀態,分別是 new runnable running blocked dead。當執行緒物件對建立後,即進入了新建狀態,如 thread t new mythread 當呼叫執行緒物件的start 方法 t.start 執行緒即進入就緒狀態。處於就緒狀態的執行緒,只是說明此執行緒...

併發程式設計(1) 執行緒基本狀態和執行緒的建立

1.新建狀態 new 執行緒物件建立後將納入新建狀態.thread t new thread 2.就緒狀態 runnable 呼叫start 進入就緒狀態 3.執行狀態 running cpu開始排程處於執行狀態的執行緒,此執行緒才真正執行 4.阻塞狀態 blocked 處於執行時的執行緒由於某種原...

Java併發程式設計系列之七 執行緒狀態

執行緒的狀態一共有6種,在任意時刻執行緒的狀態只能是其中的一種。正確理解執行緒的狀態有助於我們更容易理解執行緒。具體的執行緒狀態如下 狀態名稱 說明new 初始狀態,執行緒被構建,但是還沒有呼叫start方法 running 執行狀態 blocked 阻塞狀態,表示執行緒阻塞於鎖 waiting 等...