Да, потому что GC может собирать только объекты, недоступные для какого-либо потока, и Thread должен содержать ссылку на его работоспособность (иначе он не сможет вызвать его). Итак, ясно, что ваш объект Runnable доступен во время работы потока.
Независимо от семантики, необходимой для выполнения , ваш объект не будет GC'd, пока он больше не будет доступен для этого нового потока или любого другого; это будет по крайней мере достаточно долго, чтобы вызвать run () вашего Runnable, и на весь срок жизни потока, если этот поток сможет достичь экземпляра Runnable, поэтому ваша конструкция гарантированно безопасна по спецификации JVM.
РЕДАКТИРОВАТЬ: Потому что Даррон избивает это до смерти, и некоторые, кажется, убеждены его аргументом, я собираюсь расширить мое объяснение, основанное на его.
Предположим на данный момент, что никто, кроме самой Thread, не может вызывать Thread.run (),
В этом случае было бы правильно, чтобы реализация Thread.run () по умолчанию выглядела следующим образом:
void run() {
Runnable tmp = this.myRunnable; // Assume JIT make this a register variable.
this.myRunnable = null; // Release for GC.
if(tmp != null) {
tmp.run(); // If the code inside tmp.run() overwrites the register, GC can occur.
}
}
Я утверждаю, что в этом случае tmp все еще является ссылкой на исполняемый объект, достижимый потоком, выполняющимся в Thread.run (), и, следовательно, не подходит для GC.
Что если (по какой-то необъяснимой причине) код выглядит так:
void run() {
Runnable tmp = this.myRunnable; // Assume JIT make this a register variable.
this.myRunnable = null; // Release for GC.
if(tmp != null) {
tmp.run(); // If the code inside tmp.run() overwrites the register, GC can occur.
System.out.println("Executed runnable: "+tmp.hashCode());
}
}
Очевидно, что экземпляр, на который ссылается tmp, не может быть GC'd, пока выполняется tmp.run ().
Я думаю, что Даррон ошибочно полагает, что достижимо означает только те ссылки, которые могут быть найдены путем поиска ссылок на экземпляры, начинающихся со всех экземпляров Thread как корней, а не определяемых как ссылка, которую можно увидеть любым исполняющим потоком. Либо так, либо я ошибаюсь, веря в обратное.
Кроме того, Даррон может предположить, что JIT-компилятор вносит любые изменения, которые ему нравятся - компилятору не разрешено изменять ссылочную семантику исполняемого кода. Если я напишу код с доступной ссылкой, компилятор не сможет оптимизировать эту ссылку и заставить мой объект быть собранным, пока эта ссылка находится в области видимости.
Я не знаю деталей того, как реально достижимые объекты; Я просто экстраполирую логику, которую я считаю обязательной. Если бы мои рассуждения были неверны, то любой объект, созданный в методе и назначенный только локальной переменной в этом методе, сразу же получил бы право на сборщик мусора - очевидно, что это не так и не может быть так.
Кроме того, вся дискуссия спорна. Если единственная достижимая ссылка находится в методе Thread.run (), поскольку прогон runnable не ссылается на его экземпляр, и никакой другой ссылки на экземпляр не существует, включая неявную this , переданную методу run () (в байт-коде, а не в качестве объявленного аргумента), тогда не имеет значения, собран ли экземпляр объекта - это, по определению, не может причинить вреда, поскольку не требуется выполнять код, если неявный этот был оптимизирован . В таком случае, даже если Даррон и прав, конечный практический результат состоит в том, что конструкция, постулируемая ФП, совершенно безопасна. В любом случае. Это не важно Позвольте мне повторить это еще раз, просто для ясности - в конце анализа это не имеет значения .