package ar.com.javacuriosities.references; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; /* * Las Phantom References son una alternativa mas segura al método finalize, * ya que el finalize permite resucitar el objeto, en cambio aquí seguimos la referencia pero * podemos ejecutar operaciones luego de que fue ejecutado el método finalize. * Estas dead reference son encoladas en la cola que le pasamos por parámetro * a la hora de construir este tipo de referencias. * * El método get de este tipo de referencias siempre devuelve NULL porque la idea es hacer limpieza post-mortem * * Es la única forma que tenemos de determinar cuando un objeto es removido de la memoria */ public class Step4PhantomReferences { @SuppressWarnings("unused") public static void main(String[] args) { try { /* * Creamos una referencia a un objeto Foo del tipo Strong Reference * Nota: Si el objeto que intentamos crear la Phantom Reference * tiene el método finalize sobrescrito este no será agregado a la * Queue. Esto aplica solo para Phantom Reference */ Object foo = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); /* * Creamos una Phantom Reference al objeto, siempre que usamos este * tipo de referencia necesitamos una ReferenceQueue, la cual sirve * para ser notificado */ PhantomReference<Object> phantomReference = new PhantomReference<Object>( foo, queue); // Hacemos al objeto elegible por el GC foo = null; new Thread(new Notification(queue)).start(); // Esperamos 2s para iniciar el otro Hilo Thread.sleep(2000); System.out.println("Suggesting GC"); // Sugerimos al GC correr System.gc(); } catch (InterruptedException e) { // Log and Handle exception e.printStackTrace(); } } private static final class Notification implements Runnable { private ReferenceQueue<Object> queue; public Notification(ReferenceQueue<Object> queue) { this.queue = queue; } @SuppressWarnings("all") @Override public void run() { try { System.out.println("Waiting for GC"); /* * Aquí se bloqueara hasta que la referencia sea recolectada, * otra opción es el método poll pero este no es bloqueante, * sino que devuelve NULL si no hay referencias en la cola */ PhantomReference<Object> phantomReference = (PhantomReference<Object>) queue.remove(); System.out.println("Reference processed for GC"); } catch (InterruptedException e) { // Log and Handle exception e.printStackTrace(); } } } }