Чтобы избежать создания воскресших объектов, обычный совет (как, например, видно в в этом ответе ) состоит в том, чтобы создать свежий экземпляр объекта, а не сохранить объектсам;обычно это достигается путем копирования всех полей объекта в новый объект.
Это не «нормальный совет», даже утверждающий, что это связано с ответом.Связанный ответ начинается с « Если вам абсолютно необходимо воскресить объекты,… », что довольно ясно показывает, что это , а не совет о том, как « избегать создание воскресших объектов ».
Подход, описанный в этом ответе - это воскрешение объекта, и по иронии судьбы, это именно тот сценарий, который вы описываете как проблему , которую вы хотитерешить, воскресение объектов (тех, на которые ссылаются скопированные поля) другим финализатором объекта.
Это сохраняет все, кроме одной из проблем, связанных с финализаторами и воскресением объекта.Единственная проблема, которую он решает, заключается в том, что завершенный объект не будет снова завершен, что является наименьшей проблемой.
Когда приложение покидает объект, оно не обязательно должно быть в допустимом состоянии.Объекты должны поддерживаться в правильном состоянии только тогда, когда они предназначены для повторного использования.Например, для приложения нормально вызывать close()
на объектах, представляющих ресурсы, когда с ними сделано.Но также разумно оставлять объект в середине операции, когда происходит ошибка.Ошибочное состояние результата может быть представлено другим объектом, а другой, теперь несовместимый объект не используется.
Финализатору придется иметь дело со всеми этими возможными состояниями объекта и, что еще хуже, с неиспользуемыми состояниями объекта, вызваннымифинализаторами.Как вы узнали сами, графы объектов могут быть собраны целиком, и все их финализаторы будут выполнены в произвольном порядке или даже одновременно.Поэтому ему не нужны петли и не нужны попытки воскресения, чтобы попасть в беду.Когда объект A имеет ссылку на объект B и оба имеют финализаторы, попытка очистки A может потерпеть неудачу при необходимости B в процессе, поскольку B может быть уже завершен или даже в середине одновременного завершения.
Короче говоря, финализация даже не подходит для очистки, для которой она изначально была предназначена.Вот почему метод finalize()
устарел в Java 9.
Ваша попытка повторно использовать значения полей финализируемого объекта просто подливает масла в огонь.Просто подумайте о сценарии A → B выше.Когда финализатор A копирует значения полей в другой объект, это подразумевает копирование ссылки на B, и он не требует попытки финализатора B сделать то же самое.Уже достаточно, если финализатор B сделает то, для чего он предназначен, очистив связанные ресурсы, оставив B в непригодном для использования состоянии.
В качестве резюме моя основная проблема заключается в «задании объекта, который в данный момент находится в состоянии ожидания».завершено, безопасно создайте его копию, без случайного воскрешения каких-либо объектов, которые могут находиться в цикле ее ссылки в процессе ".
Как объяснено," объект, который в настоящее время завершается "и"безопасно »- противоречие само по себе.Не нужно взаимных попыток повторного использования, чтобы сломать его.Даже если смотреть только на оригинальную узкую формулировку проблемы, у всех ваших подходов есть проблема, заключающаяся в том, что они даже не пытаются ее предотвратить.Все они только пытаются обнаружить проблему через какое-то произвольное время после факта.
Тем не менее, нет проблемы при сравнении референта WeakReference
с какой-либо другой сильной ссылкой, такой как weakReference.get() == someStrongReference
.Слабая ссылка очищается только тогда, когда референт был убран сборщиком мусора, что означает, что сильная ссылка не может указать на нее, поэтому ответ false
для сравнения ссылки null
с someStrongReference
будет правильнымответь тогда.