Cette question a été publiée sur un site. Je n'ai pas trouvé de bonnes réponses là-bas, donc je le poste à nouveau ici.
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
}
}
Ma requête ne concerne pas l'arrêt d'un thread. Permettez-moi de reformuler ma question. La ligne A (voir le code ci-dessus) démarre un nouveau thread; et la ligne B rendent la référence de thread nulle. Ainsi, la JVM a maintenant un objet de thread (qui est en cours d'exécution) auquel aucune référence n'existe (comme t = null dans la ligne B). Donc ma question est, pourquoi ce thread (qui n'a plus de référence dans le thread principal) continue de fonctionner jusqu'à ce que le thread principal soit en cours d'exécution. D'après ce que je comprends, l'objet thread aurait dû être récupéré après la ligne B. J'ai essayé d'exécuter ce code pendant 5 minutes et plus, demandant Java Runtime pour exécuter GC, mais le thread ne fonctionne tout simplement pas Arrêtez.
J'espère que le code et la question sont clairs cette fois.
Un thread en cours d'exécution est considéré comme une racine dite de récupération de place et est l'une de ces choses qui empêche les choses d'être récupérées. Lorsque le garbage collector détermine si votre objet est ' accessible ' ou non, il le fait toujours en utilisant l'ensemble des racines du garbage collector comme points de référence.
Considérez ceci, pourquoi votre thread principal n'est-il pas récupéré, personne ne le fait référence non plus.
Comme cela a été expliqué, les threads en cours d'exécution sont, par définition, immunisés contre GC. Le GC commence son travail en scannant les "racines", qui sont jugées toujours accessibles; les racines incluent des variables globales ("champs statiques" dans Java-talk) et les piles de tous les threads en cours d'exécution (on peut imaginer que la pile d'un thread en cours référence l'instance Thread
correspondante).
Cependant, vous pouvez faire d'un thread un thread "démon" (voir Thread.setDaemon(boolean)
). Un thread démon n'est pas plus récupéré qu'un thread non démon, mais la JVM se ferme lorsque tous les threads en cours d'exécution sont des démons. Une façon de l'imaginer est que chaque thread, lorsqu'il se termine, vérifie s'il reste des threads non-daemon en cours d'exécution; sinon, le thread de terminaison force un appel System.exit()
, qui quitte la JVM (tuant les threads du démon en cours d'exécution). Ce n'est pas un problème lié au GC; d'une certaine manière, les threads sont alloués manuellement. Cependant, c'est ainsi que la JVM peut tolérer les threads semi-voyous. Ceci est généralement utilisé pour les instances Timer
.
La JVM a une référence à tous les threads en cours d'exécution.
Aucun thread (ou les éléments auxquels il fait référence) ne sera récupéré pendant qu'il est en cours d'exécution.
Le thread n'est pas récupéré car il existe des références aux threads que vous ne pouvez pas voir. Par exemple, il existe des références dans le système d'exécution.
Lorsque le fil est créé, il est ajouté au groupe de fils actuel. Vous pouvez obtenir une liste de Threads dans le groupe de threads actuel, c'est donc une autre façon d'obtenir une référence.