Java Thread Мусор собран или нет

Этот вопрос был опубликован на каком-то сайте. Я не нашел там правильных ответов, поэтому я размещаю его здесь снова.

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
    }
}

Мой запрос не о прекращении Thread. Позвольте мне перефразировать мой вопрос. Строка A (см. Код выше) запускает новую тему; и строка B делает ссылку на поток нулевой. Таким образом, JVM теперь имеет объект Thread (который находится в рабочем состоянии), к которому не существует ссылка (как t = null в строке B). Поэтому мой вопрос: почему этот поток (который больше не имеет ссылки в основном потоке) продолжает работать до тех пор, пока не будет запущен основной поток. По моему пониманию, объект потока должен был быть собранным после сборки строки B. Я попытался запустить этот код в течение 5 минут и более, запросив Java Runtime для запуска GC, но поток просто не останавливается.

Надеемся, что на этот раз и код, и вопрос понятны.

Ответ 1

Бегущая нить считается так называемым корнем сборщика мусора и является одной из тех вещей, которые не позволяют собирать мусор. Когда сборщик мусора определяет, является ли ваш объект " достижимым или нет, он всегда делает это, используя набор корней сборщика мусора в качестве контрольных точек.

Подумайте, почему ваш основной поток не собирает мусор, никто не ссылается на него.

Ответ 2

Как было объяснено, работающие потоки, по определению, невосприимчивы к GC. GC начинает свою работу путем сканирования "корней", которые считаются всегда доступными; корни включают глобальные переменные ( "статические поля" в Java-talk) и стеки всех запущенных потоков (можно предположить, что стек текущего потока ссылается на соответствующий экземпляр Thread).

Однако вы можете сделать поток потоком "демона" (см. Thread.setDaemon(boolean)). Нить демона больше не собирает мусор, чем поток не-демона, но JVM завершает работу, когда все запущенные потоки являются демонами. Один из способов представить, что каждый поток, когда он завершает работу, проверяет, остаются ли какие-то не связанные с демонами потоки; если нет, то завершающая нить заставляет вызов System.exit(), который выходит из JVM (убивая запущенные потоки демона). Это не проблема, связанная с GC; в некотором смысле, потоки распределяются вручную. Тем не менее, именно так JVM может переносить потоки с полупростой. Обычно это используется для экземпляров Timer.

Ответ 3

JVM имеет ссылку на все запущенные потоки.

Ни один нить (или вещи, на которые он ссылается) будет собирать мусор, пока он все еще работает.

Ответ 4

Тема не собирает мусор, потому что есть ссылки на потоки, которые вы не видите. Например, в системе исполнения есть ссылки.

Когда поток создается, он добавляется к текущей группе потоков. Вы можете получить список потоков в текущей группе потоков, так что это еще один способ получить ссылку на него.