2010-03-11 111 views
69

這個問題發佈在一些網站上。我沒有找到正確的答案,所以我在這裏再次發佈。Java線程垃圾收集與否

public class TestThread { 
    public static void main(String[] s) { 
     // anonymous class extends Thread 
     Thread t = new Thread() { 
      public void run() { 
       // infinite loop 
       while (true) { 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
        } 
        // as long as this line printed out, you know it is alive. 
        System.out.println("thread is running..."); 
       } 
      } 
     }; 
     t.start(); // Line A 
     t = null; // Line B 
     // no more references for Thread t 
     // another infinite loop 
     while (true) { 
      try { 
       Thread.sleep(3000); 
      } catch (InterruptedException e) { 
      } 
      System.gc(); 
      System.out.println("Executed System.gc()"); 
     } // The program will run forever until you use ^C to stop it 
    } 
} 

我的查詢不是關於停止線程。讓我重述一下我的問題。線路A(見上面的代碼)啓動一個新的線程;和B行使線程引用爲空。因此,JVM現在有一個線程對象(它處於運行狀態),其中沒有引用存在(如線B中的t = null)。 所以我的問題是,爲什麼這個線程(主線程中沒有引用)繼續運行,直到主線程運行。根據我的理解,線程對象應該在B行後面被垃圾收集。我試圖運行這段代碼5分鐘以上,請求Java運行時運行GC,但線程不停止。

希望這次代碼和問題都很清楚。

回答

102

正在運行的線程被認爲是所謂的垃圾收集根,並且是阻止垃圾收集的東西之一。當垃圾收集器確定您的對象是否爲'reachable'時,它始終使用垃圾收集器根作爲參考點。

考慮一下,爲什麼你的主線程沒有被垃圾收集,沒有人引用那個。

+10

這個答案,正如它目前的立場,引出了一個問題:線程是否可以被GC化(在它們終止之後)。由於此問題被標記爲[this one]的副本(http://stackoverflow.com/questions/10380327/java-threads-and-garbage-collector),因此應該提及線程將不再被標記爲「垃圾收集根「,因此它們可以被GC訪問。 – bluenote10 2014-08-30 09:09:18

+0

@ bluenote10正確,因此短語「正在運行的線程」。 – falstro 2014-08-30 12:18:24

+10

最後一句是滲透:「你的主線爲什麼不是垃圾......」。 – Determinant 2014-12-23 07:28:19

15

JVM具有對所有正在運行的線程的引用。

沒有線程(或它所指的東西)在它仍在運行時將被垃圾收集。

8

線程不是垃圾收集,因爲有線程的引用,你看不到。例如,運行系統中有參考。

創建線程時,它被添加到當前線程組。您可以獲取當前線程組中的線程列表,這是另一種獲取對它的引用的方法。

18

如上所述,根據定義,正在運行的線程對GC不起作用。 GC開始通過掃描被認爲始終可達的「根」來開展工作;根包含全局變量(Java-talk中的「靜態字段」)和所有正在運行的線程的堆棧(可以想象,正在運行的線程的堆棧引用相應的Thread實例)。

但是,您可以使線程成爲「守護程序」線程(請參閱Thread.setDaemon(boolean))。守護程序線程不會比非守護程序線程更多地進行垃圾收集,但當所有正在運行的線程都是守護進程時,JVM將退出。一種想象的方式是,每一個線程在終止時檢查是否還有一些非守護進程正在運行的線程;如果不是,終止線程會強制調用一個System.exit()調用,該調用將退出JVM(關閉正在運行的守護進程線程)。這不是GC相關問題;在某種程度上,線程是手動分配的。但是,這是JVM如何容忍半流氓線程的方式。這通常用於Timer實例。