1. 程式人生 > >執行緒的狀態與上下文切換

執行緒的狀態與上下文切換

Java語言中,一個執行緒從其建立、啟動到其執行結束的整個生命週期可能經歷若干個狀態,如下圖所示。

                      

Java執行緒的狀態可以通過Thread例項的getState()方法獲取。Thread.State所定義的執行緒狀態包括以下幾種。

       NEW:個剛建立而未啟動的執行緒處於該狀態。由於一個執行緒例項只能夠被啟動一次,因此一個執行緒只可能有一次處於該狀態。

       RUNNABLE:該狀態可以看成是一個符合的狀態。它包括兩個子狀態:READY和RUNNING。前者表示處於該狀態的執行緒可以被JVM的執行緒排程器(Scheduler)進行排程而使之處於RUNNING狀態。後者表示處於該狀態的執行緒正在執行,即,相應執行緒物件的run()方法中的程式碼所對應的指令正在由CPU執行。當Thread例項的yield()方法被呼叫時或者由於執行緒排程器的原因,相應執行緒的狀態會由RUNNING轉換為READY。

       BLOCKED:一個執行緒發起一個阻塞式I/O(Blocking I/O)操作後,或者試圖去獲得一個由其他執行緒持有的鎖時,相應的執行緒會處於該狀態。處於該狀態的執行緒並不會佔用CPU資源。當相應的I/O操作完成後,或者相應的鎖被其他執行緒釋放後,該執行緒的狀態又可以轉換為RUNNABLE。

      WAITING:一個執行緒執行了某些方法呼叫之後就會處於這種無限等待其他執行緒執行特定操作的狀態。這些方法包括:Object.wait()、Thread.join()和LockSupport.park()。能夠使相應執行緒從WAITING轉換到RUNNABLE的相應方法包括:Object.notify()、Object.notifyAll()和LockSupport.unpark(thread)。

       TIMED_WAITING:改狀態和WAITING類似差別在於處於該狀態的執行緒並非無限等待其他執行緒執行特定操作,而是處於有時間限制的等待狀態。當其他執行緒沒有在指定的時間內執行該執行緒所期望的特定操作時,該執行緒的狀態自動轉換為RUNNABLE。

       TERMINATED:已經執行結束的執行緒處於該狀態。由於一個執行緒例項只能夠被啟動一次,因此一個執行緒也只可能有一次處於該狀態。Thread例項的run()方法正常返回或者由於丟擲異常而提前終止都會導致相應執行緒處於該狀態。

從上述的描述可知,一個執行緒在它的整個生命週期中,只可能一次處於NEW狀態和TERMINATED狀態。而一個執行緒的狀態從RUNNABLE狀態轉換為BLOCKED、WAITING和TIMED_WAITING這幾個狀態中的任何一個狀態都意味著上下文切換(Context Switch)。

上下文切換就好比我們接聽手機電話的場景。比如,我們正在接聽一個電話並與對方討論某件事情的時候,這時候突然有另外一個來電。通常這個時候我們會跟對方說:“我先接個電話,你別結束通話”,並在腦海中記錄下和對方的討論進行到什麼程度了。然後,接聽新的來電並且告訴對方稍後會回撥並將該來電結束通話。接著,我們又會繼續先前的討論。如果在接聽新來電之前,自己腦海中沒有記錄下當時的討論進行到什麼程度了,那麼我們有可能會問對方“剛才我們講到哪裡了”這樣的問題。

多執行緒環境中,當一個執行緒的狀態由RUNNABLE轉換為非RUNNABLE(BLOCKED、WAITING或者TIMED_WAITING)時相應執行緒的上下文資訊需要被儲存,以便於相應執行緒稍後再次進入RUNNABLE狀態時能夠在之前的執行進度的基礎上繼續執行,而一個執行緒的狀態由非RUNNABLE狀態轉換進入RUNNABLE狀態時可能涉及恢復之前儲存的執行緒的上下文資訊並在此基礎上繼續執行。這種對執行緒的上下文資訊進行儲存和恢復的過程就被稱為上下文切換。