線程的生命週期通過新建(New)、就緒(Runnable)、運行(Running)、阻塞(Bolocked)和死亡(Dead)java
程序使用new關鍵字
建立一個線程以後,該線程就處於新建狀態
,僅僅由Java虛擬機爲其分配內存,並初始化其成員變量的值。不會執行線程的線程執行體。如Thread thread = new Thread()
。編程
也稱爲「可執行狀態」
,線程對象調用start()
方法後,該線程處於就緒狀態
。如thread.start()
。Java虛擬機會爲其建立方法調用棧和程序計數器(線程私有),處於就緒狀態的線程並無開始運行,只是表示該線程能夠運行,線程什麼時候運行取決於JVM中線程調度器的調度。多線程
處於就緒狀態的線程得到CPU,開始執行run()方法
的線程執行體,則該線程處於運行狀態
。(注意:線程只能從就緒狀態進入到運行狀態)併發
阻塞狀態是線程由於某種緣由放棄了CPU的使用權
,暫時中止運行,直到線程進入就緒狀態,纔有機會轉到運行狀態。當調用sleep()
、一個阻塞式IO方法
、同步鎖、等待通知、suspend()方法
掛起都會使線程進入阻塞狀態。ide
sleep()
方法主動放棄所佔用的處理器資源;IO方法
,在該方法返回以前,該線程被阻塞;同步監視器
,但該同步監視器正被其餘線程所持有;wait()
)某個通知(notify()
);suspend()
方法將該線程掛起,但這個方法易形成死鎖,應該避免使用。線程從阻塞狀態解除——進入就緒狀態的過程:函數
sleep()方法
的線程通過了指定時間;resume()
恢復方法。run()
或call()
方法執行完成,線程正常結束;Exception
或Error
;stop()
方法來結束該線程(該方法易形成死鎖,不推薦使用)注意:this
能夠經過isAlive()
方法,線程對象的isAlive()
方法返回true,即爲線程存活;返回false,即爲線程死亡。
線程處於就緒、運行、阻塞狀態時,isAlive()
返回true
;線程處於新建、死亡狀態時,isAlive()
返回false
。線程
當程序使用new關鍵字
建立了一個線程後,該線程就處於新建狀態,此時它和其餘Java對象是同樣的,只是由JVM爲其分配內存,並初始化其成員變量的值(此時線程對象沒有任何的行爲,也不執行線程執行體)。
當線程對象調用了start()
方法後,線程就處於就緒狀態,JVM爲其建立方法調用棧和程序計數器,處於這個狀態中的線程尚未真正的開始運行,只是表示這個線程此時是一個可運行狀態。什麼時候能運行?取決於JVM的線程調度器的調度。
處於就緒狀態的線程獲取CPU執行權限
,開始執行run()
方法的線程執行體,此時線程處於運行狀態。(若只有一個CPU,任什麼時候刻只能有一個線程處於運行狀態,多線程處理任務時,會給人一種併發錯覺,實際是CPU執行速度較快,多線程交織執行任務而已)3d
public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ //若線程不是就緒狀態,就拋出異常 if (threadStatus != 0) throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ //將線程添加到ThreadGroup中 group.add(this); boolean started = false; try { //經過start0()方法啓動線程 start0(); //設置線程啓動的started標誌位 started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } } }
start()
實際上經過本地方法start0()
啓動線程,會新運行一個線程,新線程會調用run()
方法。日誌
@Override public void run() { if (target != null) { target.run(); } }
target
是Runnable對象
,run()
直接調用Thread線程
的Runnable成員
的run()
方法,並不會新建一個線程。
public static native void sleep(long millis) throws InterruptedException
:讓當前正在執行的線程暫停millis毫秒,並進入阻塞狀態。public static void sleep(long millis, int nanos) throws InterruptedException
:讓當前正在執行的線程暫停millis毫秒+nanos毫微秒,並進入阻塞狀態。(不多用)一般用法就是
//讓當前線程睡眠1000毫秒,即暫定1s Thread.sleep(1000);
yield()
方法讓當前正在執行的線程暫停,但不會阻塞線程,只是讓線程轉入就緒狀態。yield()
方法讓當前線程暫停,讓系統的線程調度從新調度一次,因此會出現當某個線程調用了yield()方法後,線程調度器又從新將它調度出來執行。yield()
方法讓當前線程暫停後,只有優先級>=當前線程的處於就緒狀態的線程才能獲取CPU執行權限。public static native void yield();
:靜態方法。//讓當前線程暫停 Thread.yield();
setPriority(int newPriority)
和getPriority()
方法設置和返回指定線程的優先級。其中setPriority()方法的參數能夠是一個整數(1-10之間),也能夠是靜態常量。join()方法
讓一個線程等待另外一個線程完成的方法;就是將指定的線程加入到當前線程,這樣兩個交替執行的線程就變成了順序執行的線程,如線程A調用了線程B的join()方法,則線程A會等待線程B執行完畢後纔會繼續執行本身。join()
方法由使用線程的程序調用,調用線程調用線程t的t.join()方法後將會被阻塞,直到線程t執行完畢,調用線程才能繼續執行。通常就是用於主線程內,等待其餘線程執行完畢後,再繼續執行main()函數。public final void join() throws InterruptedException
:等待被join的線程執行完畢。public final synchronized void join(long millis) throws InterruptedException
:等待被join的線程的超時時間爲millis毫秒。若是在millis毫秒內被join的線程還未結束執行流程,則調用線程再也不等待。public final synchronized void join(long millis, int nanos) throws InterruptedException
:等待被join的線程的時間最長爲millis毫秒+nanos毫微秒。(不多用)代碼
public class JoinMethodTest { public static void main(String[] args) { System.out.println("main thread start"); Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("child thread start"); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } System.out.println("child thread finshed"); } }); thread.start(); System.out.println("main thread finshed"); } }
運行結果
main thread start main thread finshed child thread start child thread finshed
能夠從運行結果看出,main()主線程日誌打印的很快,沒有等待子線程打印就結束了。
代碼
public class JoinMethodTest { public static void main(String[] args) { System.out.println("main thread start"); Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("child thread start"); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } System.out.println("child thread finshed"); } }); thread.start(); //加入join()方法等待子線程執行完畢,才執行主線程。 try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main thread finshed"); } }
運行結果
main thread start child thread start child thread finshed main thread finshed
從運行結果能夠看出,main thread finshed
結果是在最後打印的,加入join()方法等待子線程執行完畢,才執行主線程。
start()
方法啓動線程,系統會將該線程對象的run()
方法看成線程執行體來處理。run()
方法,該方法會被當即執行,而在run()
方法返回以前其餘線程沒法併發執行(系統會將線程對象的看成一個普通對象,將run()
方法看成一個普通方法,而不是線程執行體。)start()
是啓動線程,讓線程重新建狀態變爲就緒狀態;線程獲得CPU時間片後,執行run()
中的線程執行體;start()
只能調用一次;run()
能夠重複調用。start()
,系統會把run()
方法當作線程執行體處理;若是直接調用run()
,系統會把線程對象看成普通對象,此時run()
也是一個普通方法,而不是線程執行體。run()方法只是類的一個普通方法而已,若是直接調用run方法,程序中依然只有主線程這一個線程,其程序執行路徑仍是隻有一條,仍是要順序執行,仍是要等待run方法體執行完畢後纔可繼續執行下面的代碼。。start()
源碼中實際上經過本地方法start0()
啓動線程,會新運行一個線程,新線程會調用run()
方法;而run()
源碼中target
是Runnable對象
,run()
直接調用Thread線程
的Runnable
成員的run()
方法,並不會新建一個線程。