Esta questão foi postada em algum site. Não encontrei as respostas certas lá, então estou postando aqui novamente.
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
}
}
Minha consulta não é sobre interromper um Thread. Deixe-me reformular minha pergunta. A linha A (veja o código acima) inicia um novo Thread; e a linha B torna a referência de thread nula. Portanto, a JVM agora tem um Thread Object (que está em estado de execução) para o qual não existe referência (como t = null na Linha B). Então, minha pergunta é: por que esse thread (que não tem mais referência no thread principal) continua em execução até que o thread principal esteja em execução. No meu entendimento, o objeto thread deveria ter sido coletado como lixo após a Linha B. Tentei executar este código por 5 minutos ou mais, solicitando o Java Runtime para executar GC, mas o thread simplesmente não para.
Espero que o código e a pergunta estejam claros desta vez.
child.join()
, ele tinha uma referência achild
. Se essa referência (e qualquer outra) não for descartada, o thread filho não pode ser GCed.Como explicado, os threads em execução são, por definição, imunes ao GC. O GC começa seu trabalho examinando as "raízes", que são consideradas sempre acessíveis; raízes incluem variáveis globais ("campos estáticos" no Java-talk) e as pilhas de todos os encadeamentos em execução (pode-se imaginar que a pilha de um encadeamento em execução faz referência à
Thread
instância correspondente ).No entanto, você pode transformar um thread em um thread de "daemon" (consulte Recursos
Thread.setDaemon(boolean)
). Um encadeamento daemon não é mais coletado como lixo do que um encadeamento não daemon, mas a JVM é encerrada quando todos os encadeamentos em execução são daemon. Uma maneira de imaginar isso é que cada thread, quando termina, verifica se ainda existem threads em execução que não sejam daemon; caso contrário, o encadeamento de encerramento força umaSystem.exit()
chamada, que sai da JVM (eliminando os encadeamentos do daemon em execução). Este não é um problema relacionado ao GC; de certa forma, os threads são alocados manualmente. No entanto, é assim que a JVM pode tolerar encadeamentos semi-desonestos. Isso normalmente é usado paraTimer
instâncias.fonte
A JVM tem uma referência a todos os encadeamentos em execução.
Nenhum thread (ou as coisas a que ele se refere) será coletado como lixo enquanto ainda estiver em execução.
fonte
O Thread não é coletado como lixo porque há referências aos threads que você não pode ver. Por exemplo, existem referências no sistema de tempo de execução.
Quando o Thread é criado, ele é adicionado ao grupo de threads atual. Você pode obter uma lista de Threads no grupo de threads atual, portanto, essa é outra maneira de obter uma referência a ele.
fonte