是否收集 Java 线程垃圾回收

2022-08-31 11:13:53

这个问题被张贴在一些网站上。我在那里没有找到正确的答案,所以我再次在这里发布。

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,但线程并没有停止。

希望这次代码和问题都很清楚。


答案 1

正在运行的线程被认为是所谓的垃圾回收根,并且是防止垃圾回收的东西之一。当垃圾回收器确定您的对象是否“可访问”时,它始终使用垃圾回收器根目录集作为参考点来执行此操作。

考虑一下,为什么你的主线程没有被垃圾回收,也没有人引用那个。


答案 2

如前所述,根据定义,正在运行的线程不受 GC 的影响。GC通过扫描被认为始终可以到达的“根”开始其工作;根包括全局变量(Java-talk中的“静态字段”)和所有正在运行的线程的堆栈(可以想象,正在运行的线程的堆栈引用了相应的实例)。Thread

但是,您可以将线程设置为“守护程序”线程(请参阅)。守护进程线程的垃圾回收并不比非守护程序线程多,但是当所有正在运行的线程都是守护程序时,JVM 会退出。一种想象方法是,每个线程在终止时都会检查是否仍有一些非守护程序正在运行的线程;如果不是,则终止线程强制调用,该调用将退出 JVM(杀死正在运行的守护程序线程)。这不是一个与GC相关的问题;在某种程度上,线程是手动分配的。但是,这就是 JVM 可以容忍半流氓线程的方式。这通常用于实例。Thread.setDaemon(boolean)System.exit()Timer