2012-04-30 21 views
17

Eventuali duplicati:
Java Thread Garbage collected or notJava fili e garbage collector

Si consideri la seguente classe:

class Foo implements Runnable { 

    public Foo() { 
     Thread th = new Thread (this); 
     th.start(); 
    } 

    public run() { 
    ... // long task 
    } 

} 

Se creiamo diverse istanze di Foo facendo

new Foo(); 
new Foo(); 
new Foo(); 
new Foo(); 

(notare che non manteniamo un puntatore a loro).

  1. Potrebbe quei casi essere rimosso dal garbage collector prima filettatura in run() estremità? (In altre parole: esiste alcun riferimento agli Foo oggetti?)

  2. E, nell'altra mano, saranno quei casi rimossi dal GC dopo il filo in `run()' estremità, o sono sprechiamo memoria ("perdita di memoria")?

  3. Se 1. o 2. sono un problema, qual è il modo giusto per farlo?

Grazie

+0

È possibile verificarlo molto facilmente. –

+0

@Quaternion, sì forse, ma la formulazione di quell'altra domanda è davvero "offuscata" e difficile da capire, imho. – cibercitizen1

+1

Questo non è un duplicato. La domanda collegata non affronta l'aspetto di "sarà spazzatura raccolta per niente dopo il completamento" (stavo per chiederlo specificatamente). Richiede solo/risponde all'aspetto di "non sarà GC mentre è in esecuzione". Questa domanda qui è a mio avviso migliore. – bluenote10

risposta

16
  1. Qualsiasi oggetto che fa riferimento un thread attivo non possono essere de-assegnati.
  2. Sì, le istanze verranno rimosse dal GC dopo che il thread in "run()" termina.
  3. Nessun prob.
+0

Per favore dammi dove ottieni questa conclusione. – Chao

2
  1. L'oggetto Foo fa riferimento alla discussione. Il filo è referenziato durante la sua corsa tutto il tempo. Pertanto non sarà raccolto.
  2. Nessuna perdita di memoria. La discussione terminerà e sarà raccolta dei rifiuti e dell'oggetto in questo processo.
  3. Dovrebbe funzionare correttamente.
10
  1. Potrebbe quei casi essere rimosso dal garbage collector prima filettatura in run() termina? (In altre parole: esiste un riferimento agli oggetti Foo?)

No. Sebbene il costruttore è in funzione GC non raccoglierà l'oggetto. In caso contrario, anche la più semplice:

Customer c = new Customer(); 

potrebbe non riuscire mentre il costruttore di Customer è in esecuzione. D'altra parte quando si avvia un nuovo thread, l'oggetto thread diventa una nuova radice GC, quindi tutto ciò a cui fa riferimento tale oggetto non è soggetto alla procedura di Garbage Collection.

  1. E, d'altra parte, saranno quei casi essere rimosso dal GC dopo la discussione in RUN)' estremità `(, o stiamo perdendo la memoria ('perdita di memoria')?

Una volta che il filo è fatto, non è una radice GC. Se nessun altro codice punta a quell'oggetto thread, sarà garbage collection.

  1. Se uno dei due punti 1 o 2. sono un problema, qual è il modo giusto per farlo?

Il tuo codice è giusto. Tuttavia:

  • iniziare un nuovo filo in un costruttore è una cattiva idea dal punto di unit test di vista

  • mantenere un riferimento a tutte filo conduttore potrebbe essere utile se ad esempio vuoi interrompere questi thread in seguito.

+0

@MarkoTopolnik: oh, lo fa! OP sta passando 'questo' al costruttore' Thread' che sembra essere un'istanza di 'Foo'. Questo è comunque corretto - se 'Foo' ha uno stato, tutte le variabili di stato sopravviveranno a GC perché sono referenziate da' Foo' - e 'Foo' è referenziato dal thread stesso. –

+4

L'avvio di un nuovo thread in un costruttore non è una buona idea anche dal punto di vista della sicurezza del thread. In questo semplice caso, è probabile che ci sia un problema, ma se si sottoclassi la classe e inizializzati alcuni campi finali nella funzione di costruzione della sottoclasse, si potrebbe finire con l'inizializzazione di questi ultimi prima di accedere. –

7

Avvio di un nuovo thread senza specificare un gruppo di thread sarà add it to the default group:

Se il gruppo è nullo e non v'è un responsabile della sicurezza, il gruppo è determinato con il metodo getThreadGroup del gestore della sicurezza. Se il gruppo è nullo e non esiste un gestore della sicurezza o il metodo getThreadGroup del gestore sicurezza restituisce null, il gruppo è impostato come lo stesso ThreadGroup del thread che sta creando il nuovo thread.

Il gruppo manterrà un riferimento al thread finché è attivo, quindi non può essere convertito in GC durante tale periodo.

Quando un thread termina (= quando run() restituisce per qualsiasi motivo), il thread viene rimosso dal gruppo di thread. Ciò accade nel metodo privato exit() che viene chiamato dal codice nativo. Questo è il momento in cui viene perso l'ultimo riferimento al thread e diventa idoneo per GC.

Si noti che il codice indica che ThreadGroup può essere null ma non è questo il caso. I vari controlli null servono solo a evitare le NPE nel raro caso in cui qualcosa vada storto. In Thread.init(), si otterrebbero NPE se Java non è in grado di determinare un gruppo di thread.

0

Assumendo che si stiano creando gli oggetti nel metodo di esecuzione, gli oggetti andranno fuori ambito quando il metodo di esecuzione termina e quindi saranno disponibili per la garbage collection. Esegui è solo un altro metodo. L'utilizzo dei thread o no non modifica il comportamento della raccolta dei dati inutili qui in alcun modo. Tutto ciò di cui hai bisogno è quando gli oggetti escono dall'ambito, che è generalmente legato all'ambito dei blocchi (blocco del metodo, while loop, se block, ecc.).

Quindi, dal momento che non si sta mantenendo alcun riferimento all'oggetto per cominciare, è possibile estrarre la logica che crea l'oggetto nel proprio metodo di breve durata. In questo modo l'oggetto che viene creato non dovrà essere mantenuto oltre l'ambito di tale metodo.

+0

gli oggetti Foo non vengono creati nel metodo di esecuzione, ma, ad esempio, nel main. – cibercitizen1

+0

solo un altro blocco di codice, non cambia nulla –