Java線程的生命周期
Java線程的生命周期
一個線程的產生是從我們調用了start方法開始進入Runnable狀態,即可以被調度運行狀態,并沒有真正開始運行,調度器可以將CPU分配給它,使線程進入Running狀態,真正運行其中的程序代碼。線程在運行過程中,有以下幾個可能的去向:
(1)調度器在某個線程的執行過程中將CPU分配給了其它線程,則這個線程又變為Runnable狀態,等待被調度。
(2)調度器將CPU分配給了該線程,執行過程中沒有遇到任何阻隔,運行完成直接結束,也就是run()方法執行完畢。
(3)線程在執行過程中請求鎖,卻得不到,這時候它要進入lock pool中等待對象的鎖,等到鎖后又會進入Runnable狀態,可以被調度運行。
(4)線程在執行過程中遇到wait()方法,它會被放入wait pool中等待,直到有notify()或interrupt()方法執行,它才會被喚醒或打斷進入lock pool開始等待對象鎖,等到鎖后進入Runnable狀態。
推薦在run方法中使用控制循環條件的方式來結束一個線程。
wait:告訴當前線程放棄對象鎖并進入等待狀態,直到其他線程進入同一對象鎖并調用notify為止。
notify:喚醒同一對象鎖中調用wait的第一個線程。
notifyAll:喚醒同一對象鎖中調用wait的所有線程,具有最高優先級的線程首先被喚醒并執行。
yield:如果知道已經完成了在run()方法的循環的一次迭代過程中所需要的工作,就可以給線程調度一個機制暗示:我的工作已經做的差不多了,可以讓給別的線程使用CPU了。通過調用yield()來實現。
當調用yield時,你也是在建議具有相同優先級的其他線程可以運行。
對于任何重要的控制或在調整應用時,都不恩那個依賴于yield。實際上,yield經常被誤用。
(yield并不意味著退出和暫停,只是,告訴線程調度如果有人需要,可以先拿去,我過會再執行,沒人需要,我繼續執行)
調用yield的時候鎖并沒有被釋放。
interrupt簡述
interrupt() 方法只是改變中斷狀態而已,它不會中斷一個正在運行的線程。這一方法實際完成的是,給受阻塞的線程發出一個中斷信號,這樣受阻線程就得以退出阻塞的狀態。 更確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,此時調用該線程的interrupt()方法,那么該線程將拋出一個 InterruptedException中斷異常(該線程必須事先預備好處理此異常),從而提早地終結被阻塞狀態。如果線程沒有被阻塞,這時調用 interrupt()將不起作用,直到執行到wait(),sleep(),join()時,才馬上會拋出 InterruptedException。
線 程A在執行sleep,wait,join時,線程B調用線程A的interrupt方法,的確這一個時候A會有 InterruptedException 異常拋出來。但這其實是在sleep,wait,join這些方法內部會不斷檢查中斷狀態的值,而自己拋出的InterruptedException。 如果線程A正在執行一些指定的操作時如值,for,while,if,調用方法等,不會去檢查中斷狀態,則線程A不會拋出 InterruptedException,而會一直執行著自己的操作。
注意:
當線程A執行到wait(),sleep(),join()時,拋出InterruptedException后,中斷狀態已經被系統復位了,線程A調用Thread.interrupted()返回的是false。
如果線程被調用了interrupt(),此時該線程并不在wait(),sleep(),join()時,下次執行wait(),sleep(),join()時,一樣會拋出InterruptedException,當然拋出后該線程的中斷狀態也會被系統復位。
1. sleep() &interrupt()
線程A正在使用sleep()暫停著: Thread.sleep(100000),如果要取消它的等待狀態,可以在正在執行的線程里(比如這里是B)調用a.interrupt()[a是線程A對應到的Thread實例],令線程A放棄睡眠操作。即,在線程B中執行a.interrupt(),處于阻塞中的線程a將放棄睡眠操作。
當在sleep中時線程被調用interrupt()時,就馬上會放棄暫停的狀態并拋出InterruptedException。拋出異常的,是A線程。
2. wait() &interrupt()
線程A調用了wait()進入了等待狀態,也可以用interrupt()取消。不過這時候要注意鎖定的問題。線程在進入等待區,會把鎖定解除,當對等待中的線程調用interrupt()時,會先重新獲取鎖定,再拋出異常。在獲取鎖定之前,是無法拋出異常的。
3. join() &interrupt()
當線程以join()等待其他線程結束時,當它被調用interrupt(),它與sleep()時一樣,會馬上跳到catch塊里.。
注意,調用的interrupt()方法,一定是調用被阻塞線程的interrupt方法。如在線程a中調用線程t.interrupt()。