執行緒各種狀態

berber78發表於2015-06-02

一、執行緒有四種狀態,任何一個執行緒肯定處於這四種狀態中的一種: 
1) 產生(New):執行緒物件已經產生,但尚未被啟動,所以無法執行。如通過new產生了一個執行緒物件後沒對它呼叫start()函式之前。 
2) 可執行(Runnable):每個支援多執行緒的系統都有一個排程器,排程器會從執行緒池中選擇一個執行緒並啟動它。當一個執行緒處於可執行狀態時,表示它可能正處於執行緒池中等待排排程器啟動它;也可能它已正在執行。如執行了一個執行緒物件的start()方法後,執行緒就處於可執行狀態,但顯而易見的是此時執行緒不一定正在執行中。 
3) 死亡(Dead):當一個執行緒正常結束,它便處於死亡狀態。如一個執行緒的run()函式執行完畢後執行緒就進入死亡狀態。 
4) 停滯(Blocked):當一個執行緒處於停滯狀態時,系統排程器就會忽略它,不對它進行排程。當處於停滯狀態的執行緒重新回到可執行狀態時,它有可能重新執行。如通過對一個執行緒呼叫wait()後,執行緒就進入停滯狀態,只有當再次對該執行緒呼叫notify或notifyAll後它才能再次回到可執行狀態。

- sleep 之後還會佔用 CPU 資源,而貌似等待就不會;

- sleep()使當前執行緒進入停滯狀態,所以執行sleep()的執行緒在指定的時間內肯定不會執行;

- sleep()可使優先順序低的執行緒得到執行的機會,當然也可以讓同優先順序和高優先順序的執行緒有執行的機會;

- yield()只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行;

- yield()只能使同優先順序的執行緒有執行的機會;
- 當呼叫wait()後,執行緒會釋放掉它所佔有的“鎖標誌”,從而使執行緒所在物件中的其它synchronized資料可被別的執行緒使用;

- 要想用wait方法必須先加同步鎖。wait不是針對執行緒Thread/Runnable的,而是針對鎖物件的,假設某個 Object lock = new Object();執行緒1(比如消費者執行緒)呼叫lock.wait()方法後,執行緒1就停下,直到其他某個執行緒(比如生產者執行緒)呼叫了lock.notify()或者lock.notifyAll();喚醒一個或者多個等待lock被喚醒的執行緒(此例中的執行緒 1)。呼叫wait之前,需要對lock同步synchronized (lock) {...}如果只是想讓當前執行緒停下一段時間 Thread.sleep(毫秒數)。如果沒有在同步塊中呼叫wait,會報IllegalMonitorStateException。

二、用法:
1.sleep():在指定的毫秒數內讓當前正在執行的執行緒休眠(暫停執行),此操作受到系統計時器排程程式精度和準確性的影響。由於sleep()方法是Thread類的方法,因此它不能改變物件的機鎖。所以當在一個Synchronized方法中呼叫sleep()時,執行緒雖然休眠了,但是物件的機鎖沒有被釋放,其他執行緒仍然無法訪問這個物件。sleep()方法不需要在同步的程式碼塊中執行。但是sleep()可以通過interrupt()方法打斷執行緒的暫停狀態,從而使執行緒立刻丟擲InterruptedException。
2.wait()和notify()和notifyAll():wait()方法則會線上程休眠的同時釋放掉機鎖,其他執行緒可以訪問該物件。wait()必須在同步的程式碼塊中執行。當一個執行緒執行到wait()方法時,它就進入到一個和該物件相關的等待池,同時失去了物件的機鎖,可以允許其它的執行緒執行一些同步操作。但是wait()可以通過interrupt()方法打斷執行緒的暫停狀態,從而使執行緒立刻丟擲InterruptedException。wait可以讓同步方法或者同步塊暫時放棄物件鎖,而將它暫時讓給其它需要物件鎖的人(這 裡應該是程式塊,或執行緒)用,這意味著可在執行wait()期間呼叫執行緒物件中的其他同步方法!在其它情況下(sleep啊,suspend啊),這是不可能的.但是注意前面說的,只是暫時放棄物件鎖,暫時給其它執行緒使用,我wait所在的執行緒還是要把這個物件鎖收回來的呀。wait什麼?就是wait別人用完了還給我啊!好,那怎麼把物件鎖收回來呢?第一種方法,限定借出去的時間.在wait()中設定引數,比如wait(1000),以毫秒為單位,就表明我只借出去1秒中,一秒鐘之後,我自動收回.第二種方法,讓借出去的人通知我,他用完了,要還給我了.這時,我馬上就收回來. 哎,假如我設了1小時之後收回,別人只用了半小時就完了,那怎麼辦呢?靠!當然用完了就收回了,還管我設的是多長時間啊.那麼別人怎麼通知我呢?相信大家都可以想到了,notify(),這就是最後一句話"而且只有在一個notify()或notifyAll()發生變化的時候,執行緒才會被喚醒"的意思 了.notify()喚醒在此物件監視器(或者說,此物件相關的等待池)上等待的單個執行緒。當它被一個notify()方法喚醒時,等待池中的執行緒就被放到了鎖池中。該執行緒將等待從鎖池中獲得機鎖,然後回到wait()前的中斷現場。notifyAll()喚醒在此物件監視器(或者說,此物件相關的等待池)上等待的所有執行緒。
3.yield():yield()方法是停止當前執行緒,讓同等優先權的執行緒執行。如果沒有同等優先權的執行緒,那麼Yield()方法將不會起作用。 
4.interrupt():interrupt() 中斷執行緒。需要注意的是,InterruptedException是執行緒自己從內部丟擲的,並不是interrupt()方法丟擲的。對某一執行緒呼叫 interrupt()時,如果該執行緒正在執行普通的程式碼,那麼該執行緒根本就不會丟擲InterruptedException。但是,一旦該執行緒進入到 wait()/sleep()/join()後,就會立刻丟擲InterruptedException(按:個人理解,對正常狀態的執行緒執行interrupt不會丟擲InterruptedException,對wait()/sleep()/join()狀態的才會丟擲)。
5.suspendresume():已廢棄。
6.join()join() 方法使當前執行緒停下來等待,直至另一個呼叫join方法的執行緒終止。值得注意的是,執行緒的在被啟用後(按:另一個呼叫join方法的執行緒終止)不一定馬上就執行,而是進入到可執行執行緒的佇列中。但是join()可以通過interrupt()方法打斷執行緒的暫停狀態,從而使執行緒立刻丟擲InterruptedException。

各個方法之間的區別

執行緒方法名稱

是否釋放同步鎖

是否需要在同步的程式碼塊中呼叫

方法是否已廢棄

是否可以被中斷

sleep()

wait()

suspend

   

 

resume()

   

 

join()

   

相關文章