В Java переопределение метода finalize
получает плохой рэп, хотя я не понимаю, почему. Классы, такие как FileInputStream
используют его для обеспечения того, чтобы close
вызывали FileInputStream
как на Java 8, так и на Java 10. Тем не менее, Java 9 представил java.lang.ref.Cleaner
который использует механизм PhantomReference вместо завершения GC. Сначала я подумал, что это просто способ добавить финализацию к сторонним классам. Однако пример, приведенный в его javadoc, показывает прецедент, который можно легко переписать с помощью финализатора.
Должен ли я переписывать все мои методы finalize
с точки зрения Cleaner? (Разумеется, у меня их мало. Просто некоторые классы, которые используют ресурсы ОС, в частности, для взаимодействия CUDA).
Как я могу сказать, Cleaner (через PhantomReference) избегает некоторых опасностей finalizer
. В частности, у вас нет доступа к очищенному объекту, и вы не можете его воскресить или какие-либо его поля.
Однако это единственное преимущество, которое я вижу. Чистота также нетривиальна. Фактически, он и финализация используют ReferenceQueue
! (Разве вам не нравится, как легко читать JDK?) Это быстрее, чем финализация? Не позволяет ли ждать двух GC? Избежит ли это изнурение кучи, если многие объекты поставлены в очередь для очистки? (Ответ всем тем, как мне кажется, не будет.)
Наконец, на самом деле ничего не гарантируется, чтобы остановить вас от ссылки на целевой объект в процессе очистки. Будьте внимательны, прочитайте длинную записку API! Если вы в конечном итоге ссылаетесь на объект, весь механизм будет тихо ломаться, в отличие от финализации, которая всегда пытается обмякнуть. Наконец, в то время как поток финализации управляется JVM, создание и хранение потоков Cleaner - ваша собственная ответственность.