Этот вопрос был размещен на каком-то сайте. Я не нашел там правильных ответов, поэтому снова публикую здесь.
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 теперь имеет объект потока (который находится в рабочем состоянии), на который не существует ссылки (как t = null в строке B). Итак, у меня вопрос: почему этот поток (который больше не имеет ссылки в основном потоке) продолжает работать до тех пор, пока не будет запущен основной поток. Насколько я понимаю, объект потока должен был быть обработан сборщиком мусора после строки B. Я пытался запустить этот код в течение 5 минут и более, запрашивая среду выполнения Java для запуска GC, но поток просто не останавливается.
Надеюсь, на этот раз и код, и вопрос ясны.
child.join()
, он ссылается наchild
. Если эта ссылка (и любая другая) не отбрасывается, дочерний поток не может быть GCed.Как было объяснено, запущенные потоки по определению невосприимчивы к GC. GC начинает свою работу со сканирования «корней», которые считаются всегда достижимыми; Корни включают глобальные переменные («статические поля» в Java-talk) и стеки всех запущенных потоков (можно представить, что стек работающего потока ссылается на соответствующий
Thread
экземпляр).Однако вы можете сделать поток потоком «демона» (см
Thread.setDaemon(boolean)
. Ресурсы ). Поток демона не более сборщик мусора, чем поток, не являющийся демоном, но JVM завершается, когда все запущенные потоки являются демонами. Один из способов представить это состоит в том, что каждый поток, когда он завершается, проверяет, остались ли какие-нибудь запущенные потоки, не являющиеся демонами; в противном случае завершающийся потокSystem.exit()
вызывает вызов, который завершает JVM ( завершая запущенные потоки демона). Это не проблема, связанная с GC; в некотором смысле потоки распределяются вручную. Однако именно так JVM может терпеть полу-мошеннические потоки. Обычно это используется дляTimer
экземпляров.источник
JVM имеет ссылку на все запущенные потоки.
Ни один поток (или то, на что он ссылается) не будет собираться сборщиком мусора, пока он еще выполняется.
источник
Поток не собирается сборщиком мусора, потому что есть ссылки на потоки, которые вы не видите. Например, есть ссылки в системе выполнения.
Когда поток создается, он добавляется в текущую группу потоков. Вы можете получить список потоков в текущей группе потоков, так что это еще один способ получить ссылку на него.
источник