此问题发布在某些网站上。我没有在那里找到正确的答案,所以我再次在这里发布。
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行使线程引用为null。因此,JVM现在有一个没有引用的线程对象(处于运行状态)(在线B中为t = null)。 所以我的问题是,为什么这个线程(主线程中没有引用)继续运行直到主线程运行。根据我的理解,线程对象应该在B行后进行垃圾收集。我尝试运行此代码5分钟以上,请求Java运行时运行GC,但线程不会停止。
希望这次代码和问题都清楚。
答案 0 :(得分:114)
正在运行的线程被认为是所谓的垃圾收集根,并且是保持垃圾收集的东西之一。当垃圾收集器确定您的对象是否为“reachable”时,它总是使用垃圾收集器根集合作为参考点。
考虑一下,为什么你的主线程没有被垃圾收集,也没有人引用那个。
答案 1 :(得分:22)
正如所解释的那样,根据定义,运行线程对GC免疫。 GC通过扫描“根”开始工作,这些“根”被认为总是可以到达的;根包括全局变量(Java-talk中的“静态字段”)和所有正在运行的线程的堆栈(可以想象正在运行的线程的堆栈引用相应的Thread
实例)。
但是,您可以将线程设为“守护程序”线程(请参阅Thread.setDaemon(boolean)
)。守护程序线程不会比非守护程序线程更多地进行垃圾收集,但是当所有正在运行的线程都是守护程序时,JVM会退出。想象一下的一种方法是每个线程在终止时检查是否还有一些非守护进程正在运行的线程;如果没有,则终止线程强制进行System.exit()
调用,该调用将退出JVM(终止正在运行的守护程序线程)。这不是与GC相关的问题;在某种程度上,线程是手动分配的。但是,这就是JVM可以容忍半流氓线程的方式。这通常用于Timer
个实例。
答案 2 :(得分:17)
JVM引用了所有正在运行的线程。
没有线程(或它引用的东西)在它仍在运行时将被垃圾收集。
答案 3 :(得分:11)
线程不是垃圾回收,因为存在对您无法看到的线程的引用。例如,运行时系统中有引用。
创建线程时,它将添加到当前线程组。您可以在当前线程组中获取一个Threads列表,这是另一种获取对它的引用的方法。