Ответ 1
- Любой объект, на который ссылается активный поток, не может быть выделен.
- Да, экземпляры будут удалены GC после завершения потока в `run() '.
- Нет проблем.
Возможный дубликат:
Собирается сборка Java Thread Garbage
Рассмотрим следующий класс:
class Foo implements Runnable {
public Foo () {
Thread th = new Thread (this);
th.start();
}
public run() {
... // long task
}
}
Если мы создадим несколько экземпляров Foo
, выполнив
new Foo();
new Foo();
new Foo();
new Foo();
(обратите внимание, что мы не сохраняем указатель на них).
Могут ли эти экземпляры удалить сборщик мусора раньше
заканчивается нить в run()
? (Другими словами: есть ли какая-либо ссылка
к объектам Foo
?)
И, с другой стороны, эти экземпляры будут удалены GC после завершения потока в `run() ', или мы теряем память ( "утечка памяти" )?
Если один или 2. являются проблемой, какой правильный способ это сделать?
Спасибо
- Могут ли эти экземпляры удаляться сборщиком мусора до завершения потока в run()? (Другими словами: есть ли ссылка на объекты Foo?)
Нет. Пока конструктор работает, GC не будет собирать объект. В противном случае даже самые простые:
Customer c = new Customer();
может завершиться неудачно, пока работает конструктор Customer
. С другой стороны, когда вы начинаете новый поток, объект потока становится новым корнем GC, поэтому все, на что ссылается этот объект, не является объектом сбора мусора.
- И, с другой стороны, эти экземпляры будут удалены GC после завершения потока в `run() ', или мы теряем память ( "утечка памяти" )?
Как только поток будет выполнен, он больше не является корнем GC. Если никакой другой код не указывает на этот объект потока, он будет собирать мусор.
- Если один или 2. являются проблемой, какой правильный способ сделать это?
Ваш код в порядке. Однако:
запуск нового потока в конструкторе - плохая идея с точки зрения тестирования единицы измерения
сохранение ссылки на весь текущий поток может быть полезным, если, например, вы хотите прервать эти потоки позже.
Запуск нового потока без указания группы потоков будет добавить его в группу по умолчанию:
Если группа имеет значение null и существует менеджер безопасности, группа определяется методом getThreadGroup диспетчера безопасности. Если группа имеет значение NULL и не существует диспетчера безопасности, или метод getThreadGroup для администратора безопасности возвращает значение null, то группа будет одинаковой ThreadGroup как поток, создающий новый поток.
Группа будет ссылаться на поток, пока он жив, поэтому он не может быть GC'd в течение этого времени.
Когда поток завершается (= когда run()
возвращает по какой-либо причине), поток удаляется из группы потоков. Это происходит в частном методе exit()
, который вызывается из собственного кода. Это момент времени, когда последняя ссылка на поток теряется и становится доступной для GC.
Обратите внимание, что код указывает, что ThreadGroup
может быть null
, но это не так. Различные нулевые проверки - это просто, чтобы избежать NPE в редком случае, что что-то пошло не так. В Thread.init()
вы получите NPE, если Java не сможет определить группу потоков.
Foo
ссылается на Thread. Тема ссылается во время ее запуска все время. Поэтому сбор мусора не будет.Foo
.Предполагая, что вы создаете объекты в методе run, объекты выйдут из области действия при выходе из метода run, а затем будут доступны для сбора мусора. Выполнить - это еще один метод. Используя потоки или нет, это никак не изменяет поведение коллекции мусора. Все, о чем вам нужно позаботиться, это когда объекты выходят за рамки, которые обычно привязаны к блокировке области (блок метода, while loop, if block и т.д.).
Итак, поскольку вы не храните ссылки на объект для начала, вы можете извлечь логику, которая создает объект в свой собственный короткий метод. Таким образом, создаваемый объект не должен оставаться за пределами этого метода.