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