PhantomReference and its usage

PhantomReference is the weakest reference. Its get method always returns null. And it can only be constructed with ReferenceQueue. Check below code.

import java.lang.ref.PhantomReference;
import java.lang.ref.WeakReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;

public class PhantomRefTest {
  static class Demo {
    String s;
    public Demo(String s) {
      this.s = s;
    }
    public String toString() {
      return s;
    }
  }

  public static void main(String ...args) {
    ReferenceQueue<Demo> q = new ReferenceQueue<>();
    PhantomReference<Demo> ref = new PhantomReference<>(new Demo("Phantom"), q);
    WeakReference<Demo> w = new WeakReference<>(new Demo("Weak"), q);
    System.gc();
    try {
      Thread.sleep(2000);
    } catch(Exception e) {
      e.printStackTrace();
    }
    new Thread(() -> {
      while(true) {
        try {
          Reference<Demo> refd = (Reference<Demo>)q.remove();
          Field f = Reference.class.getDeclaredField("referent");
          f.setAccessible(true);
          System.out.println(refd.getClass()); // print class
          System.out.println(f.get(refd)); //print null for WeakReference, Phantom for PhantomReference
        } catch(Exception e) {
          e.printStackTrace();
        }
      }
    }).start();
  }
}

Both reference object will be added to the ReferenceQueue if there’s no any other ref of the referent. But WeakReference’s referent has been garbage collected, whereas PhantomReference is not. We need to call ref.clear() method or set the PhantomReference to null to hint GC. It’s the case before jdk8. Starting from jdk9, there’s no need to call ref.clear() method for PhantomReference.

PhantomReference is suitable to do some cleanup work in the background. Such as in the FileCleaningTracker of commons-io, it starts a daemon thread to poll from the ReferenceQueue to do file cleanup work in background.