之前在學習操做系統的時候,一直記得的父線程死後,子線程也消失了。然而今天在查資料中,發現有點疑惑,在此記錄一下。 java
Java編寫的程序都運行在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是經過線程來實現的。 安全
每用java命令啓動一個java應用程序,就會啓動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它本身。在這個JVM環境中,全部程序代碼的運行都是以線程來運行的。JVM找到程序的入口點main(),而後運行main()方法,這樣就產生了一個線程,這個線程稱之爲主線程。當main方法結束後(沒有其餘線程時),主線程運行完成。JVM進程也隨即退出。 服務器
操做系統將進程線程進行管理,輪流(沒有固定的順序)分配每一個進程很短的一段時間(不必定是均分),而後在每一個進程內部,程序代碼本身處理該進程內部線程的時間分配,多個線程之間相互的切換去執行,這個切換時間也是很是短的。 jvm
對於程序來講,若是主進程在子進程還未結束時就已經退出,那麼Linux內核會將子進程的父進程ID改成1(也就是init進程),當子進程結束後會由init進程來回收該子進程。 ide
那若是是把進程換成線程的話,會怎麼樣呢?假設主線程在子線程結束前就已經退出,子線程會發生什麼? 學習
首先咱們來看一個網上不少人的例子: spa
package test; public class Test1 extends Thread { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("我還活着"); } } public static void main(String[] args) throws InterruptedException { Thread t = new Test1(); t.start(); Thread.sleep(5000); System.out.println("Main End"); } }
我還活着 我還活着 Main End 我還活着 我還活着
package test; public class Test extends Thread { @Override public void run() { Thread sonthread = new a(); sonthread.start(); } public static void main(String[] args) throws InterruptedException { Thread fatherThread = new Test(); fatherThread.start(); Thread.sleep(5000); fatherThread.interrupt(); Thread.sleep(2000); System.out.println("fatherThread.isAlive()? "+fatherThread.isAlive()); } } class a extends Thread { @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我還活着"); } } }
我還活着 我還活着 我還活着 我還活着 我還活着 我還活着 fatherThread.isAlive()? false 我還活着 我還活着 我還活着
查了不少資料獲得瞭解答。 操作系統
若是main方法中沒有建立其餘線程,那麼當main方法返回時JVM就會結束Java應用程序。但若是main方法中建立了其餘線程,那麼JVM就要在主線程和其餘線程之間輪流切換,保證每一個線程都有機會使用CPU資源,main方法返回(主線程結束)JVM也不會結束,要一直等到該程序全部線程所有結束才結束Java程序(另一種狀況是:程序中調用了Runtime類的exit方法,而且安全管理器容許退出操做發生。這時JVM也會結束該程序)。 .net
那麼又有個思考,JVM是怎麼知道線程都結束的呢? 線程
JVM中有一個線程DestroyJavaVM,執行main()的線程在main執行完後調用JNI中的jni_DestroyJavaVM()方法喚起DestroyJavaVM線程。JVM在Jboss服務器啓動以後,就會喚起DestroyJavaVM線程,處於等待狀態,等待其它線程(java線程和native線程)退出時通知它卸載JVM。線程退出時,都會判斷本身當前是不是整個JVM中最後一個非deamon線程,若是是,則通知DestroyJavaVM線程卸載JVM。ps:擴展一下:1.若是線程退出時判斷本身不爲最後一個非deamon線程,那麼調用thread->exit(false),並在其中拋出thread_end事件,jvm不退出。2.若是線程退出時判斷本身爲最後一個非deamon線程,那麼調用before_exit()方法,拋出兩個事件: 事件1:thread_end線程結束事件、事件2:VM的death事件。而後調用thread->exit(true)方法,接下來把線程從active list卸下,刪除線程等等一系列工做執行完成後,則通知正在等待的DestroyJavaVM線程執行卸載JVM操做。
因此第一個例子時,主線程運行完,可是它不是最後一個非守護線程,因此JVM並無退出,因此子線程還會繼續運行。
第二個例子。主線程一直在,因此JVM不會退出。當父線程死去後,子線程還在運行。說明父線程的生命週期與子線程沒有關係。
1. http://warnerhit.iteye.com/blog/1407484
2. http://liyuanlife.com/blog/2015/04/08/influence-of-main-threads-exiting-to-child-thread/
3. http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp47
4. http://jinguo.iteye.com/blog/747256