Java中的父線程與子線程

之前在學習操做系統的時候,一直記得的父線程死後,子線程也消失了。然而今天在查資料中,發現有點疑惑,在此記錄一下。 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
我還活着
我還活着



上文說了 JVM找到程序的入口點main(),而後運行main()方法,這樣就產生了一個線程,這個線程稱之爲主線程。當main方法結束後(沒有其餘線程時),主線程運行完成。JVM進程也隨即退出。然而上述輸出代表當main()運行到最後後,子線程依然在輸出。因此你們就得出告終論,父線程要等待子線程完成後纔會退出。然而咱們再看個例子:

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

相關文章
相關標籤/搜索