2010-03-11 9 views
69

Questa domanda è stata pubblicata su alcuni siti. Non ho trovato le risposte giuste lì, quindi lo sto postando di nuovo qui.Thread Java Rifiuti raccolti o meno

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 
    } 
} 

La mia domanda non riguarda l'interruzione di una discussione. Lasciatemi riformulare la mia domanda. La riga A (vedere il codice sopra) inizia una nuova discussione; e la linea B rende il riferimento del filo nullo. Quindi, la JVM ora ha un oggetto Thread (che è in esecuzione) a cui non esiste alcun riferimento (come t = null nella Linea B). Quindi la mia domanda è, perché questo thread (che non ha più riferimenti nel thread principale) continua a essere in esecuzione fino a quando il thread principale è in esecuzione. Per mia comprensione, l'oggetto thread avrebbe dovuto essere garbage collection post Line B. Ho provato a eseguire questo codice per 5 minuti e oltre, richiedendo Java Runtime per eseguire GC, ma il thread non si ferma.

Spero che sia il codice sia la domanda siano chiari questa volta.

risposta

102

Un thread in esecuzione è considerato una cosiddetta radice di garbage collection ed è una di quelle cose che impedisce che vengano raccolti dati inutili. Quando il garbage collector determina se il tuo oggetto è 'reachable' o no, lo fa sempre usando il set di root del garbage collector come punti di riferimento.

Considerate questo, perché il vostro thread principale non viene raccolto dai rifiuti, nessuno fa riferimento a quello.

+10

Questa risposta, al momento attuale, solleva la questione se i thread possono essere sottoposti a GC (dopo la loro chiusura). Poiché questa domanda è contrassegnata come duplicato di [questo] (http://stackoverflow.com/questions/10380327/java-threads-and-garbage-collector), è necessario ricordare che i thread non saranno più contrassegnati come " root di garbage collection "dopo che sono terminati e quindi diventano accessibili per GC. – bluenote10

+0

@ bluenote10 corretto, quindi la frase "thread in esecuzione". – falstro

+10

L'ultima frase è penetrante: "perché il tuo thread principale non è spazzatura ...". – Determinant

15

La JVM ha un riferimento a tutti i thread in esecuzione.

Nessun thread (o le cose a cui si riferisce) verrà raccolto automaticamente mentre è ancora in esecuzione.

8

La discussione non è raccolta dati inutili perché ci sono riferimenti ai thread che non è possibile visualizzare. Ad esempio, ci sono riferimenti nel sistema di runtime.

Quando viene creato il thread, viene aggiunto al gruppo di thread corrente. È possibile ottenere un elenco di thread nel gruppo di thread corrente, in modo che sia un altro modo per ottenere un riferimento ad esso.

18

Come è stato spiegato, i thread in esecuzione sono, per definizione, immuni a GC. Il GC inizia il suo lavoro scansionando "roots", che sono considerate sempre raggiungibili; root include le variabili globali ("campi statici" in Java-talk) e gli stack di tutti i thread in esecuzione (si può immaginare che lo stack di un thread in esecuzione faccia riferimento all'istanza Thread corrispondente).

Tuttavia, è possibile creare un thread con un thread "daemon" (vedere Thread.setDaemon(boolean)). Un thread daemon non è più raccolto da garbage di un thread non daemon, ma la JVM si chiude quando tutti i thread in esecuzione sono daemon. Un modo per immaginarlo è che ogni thread, quando termina, controlla se rimangono alcuni thread in esecuzione non demone; in caso contrario, il thread terminante forza una chiamata System.exit(), che esce dalla JVM (eliminando i thread del daemon in esecuzione). Questo non è un problema relativo al GC; in un certo senso, i thread sono allocati manualmente. Tuttavia, questo è il modo in cui la JVM può tollerare i thread semi-canaglia. Viene in genere utilizzato per le istanze Timer.