2012-12-16 37 views
28

我在教自己的Java線程,我注意到一些讓我困惑的東西。我做了一個名爲engine的課,實施Runnable。 run方法只打印「Hello World」,睡一會兒,然後重複。爲什麼線程超過Java中的主要方法?

在我的主要方法,我有:

public static void main(String[] args) { 
    Thread thread = new Thread(engine); 
    thread.start(); 
    System.out.println("Done."); 
} 

如我所料,我看到 「Hello World」 和 「完成」。印刷速度很快,這意味着主要方法已達到結束,但我沒有想到的是,即使在主結束後,我開始保持運行的線程。

爲什麼即使在主退出後程序仍繼續執行?我會認爲,當主要退出過程將終止,所有的線程將被強制清理。這是否意味着每個線程都必須顯式加入/終止Java程序才能終止?

+0

我的猜測是程序在所有線程完成時完成。如果你的線程在一個循環中,那麼程序直到終止纔會結束。 – gsingh2011

+0

爲了確保我不會瘋狂(我總是在不考慮C的情況下編寫連接),如果我在C程序中這樣做了,那麼它會強制終止該線程,對吧? –

回答

26

如果你希望你的程序退出時的主要方法完成,考慮讓線程守護進程。但是請注意,在主完成時,守護線程將被中止。
您可以創建一個守護進程THEAD像這樣:

Thread t = new Thread(...); 
t.setDaemon(true); 

所有非守護線程是用戶線程。這些線程正在阻止jvm關閉。

+4

「當主進程退出時,守護線程將被中止。只有*所有創建的線程都是守護進程,情況纔是如此。規則是一旦只有正在運行的線程是守護進程線程,JVM纔會退出,但守護進程肯定會超過主線程。 – Boann

9

用戶線程繼續獨立於其父線程的生命週期運行,即創建者線程。因此,在線程終止之前,您必須通過調用Thread.join明確加入線程。

Javadoc of Thread

當Java虛擬機啓動時,通常有一個 非守護線程(它通常會調用命名爲主要的一些 指定類中的方法)。 Java虛擬機繼續直至出現以下任何一種情況發生時執行 主題:Runtime類的

  1. 退出方法被調用和安全 管理器允許退出操作發生。

  2. 所有不是守護線程的線程都已死亡,可以通過將 從調用返回到run方法,或通過拋出一個異常來傳播超出run方法。

如果你想,即使一個線程t正在運行的JVM終止,你應該make thread t a daemon thread

t.setDaemon(true); 
+1

查看我更新的答案。 – reprogrammer

+0

我最初專注於回答「這是否意味着每個線程都必須顯式加入/終止Java程序才能終止?」。然後,我將它擴展到「爲什麼」部分。 – reprogrammer

+0

謝謝:)只是爲了確保我不會瘋了(我總是在不考慮C的情況下編寫連接),如果我在C程序中這樣做了,那麼它會強制終止線程,對吧? –

27

因爲這就是它的工作原理。當調用System.exit()時,或者最後一個非守護線程停止運行時,程序退出。

它是有道理的。如果沒有這個規則,例如,每個構成GUI的Java程序都必須等待()以避免程序立即退出。

+0

感謝您的回答,有用的方式看看:) +1 –

10

線程有兩種類型,用戶和守護進程。該進程在沒有更多用戶線程時終止。主線程始終是用戶線程。您啓動的線程也是一個用戶線程,因此只要運行該進程,該進程就會保持活動狀態。

在啓動它之前調用setDaemon(true)將使您的進程在您的main()函數返回時立即終止(或多或少)。

+0

感謝您的回答:) –

7

Java Language Specification section 12.8表示:

12.8。計劃退出

的程序終止其所有活動和退出時的兩兩件事之一 情況:

所有這一切都沒有守護線程終止線程。

有些線程調用Runtime類或類系統, 的退出方式和退出操作不是由安全管理器禁止。

這意味着主線程完成是不夠的。

如果您確實希望在主線程結束時退出,您需要使用Thread#setDaemon或使用Thread#join按照您最初的建議使新線程成爲守護進程。

0

主線程也是一個正在創建的用戶線程,它的lifecylce與任何其他用戶線程相似。
除非將線程設置爲守護程序線程,否則其他用戶線程不會因任何原因而依賴主線程。 一旦主線程完成了它的工作,它就結束了(它不會結束其他用戶線程,也不會結束進程,因爲其他用戶線程正在運行)。

相關問題