Java Thread Мусор собран или нет - PullRequest
81 голосов
/ 11 марта 2010

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

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 теперь есть объект Thread (который находится в рабочем состоянии), на который нет ссылки (как t = null в строке B). Поэтому мой вопрос: почему этот поток (на который больше нет ссылок в основном потоке) продолжает работать, пока не будет запущен основной поток. Насколько я понимаю, объект потока должен был собирать мусор после строки B. Я пытался запустить этот код в течение 5 минут и более, запрашивая Java Runtime для запуска GC, но поток просто не останавливался.

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

Ответы [ 4 ]

115 голосов
/ 11 марта 2010

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

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

22 голосов
/ 11 марта 2010

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

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

17 голосов
/ 11 марта 2010

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

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

11 голосов
/ 11 марта 2010

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

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

...