import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
/**
* @author Peter Chng
*/
class Ideone {
// Just so we have a non-primitive, non-interned object that will be GC'd.
public static class SampleObject<T> {
private final T value;
public SampleObject(final T value) {
this.value = value;
}
@Override
return String.
valueOf(this.
value); }
}
public static class PhantomReferenceMetadata<T, M> extends PhantomReference<T> {
// Some metadata stored about the object that will be used during some cleanup actions.
private final M metadata;
public PhantomReferenceMetadata(final T referent, final ReferenceQueue<? super T> q,
final M metadata) {
super(referent, q);
this.metadata = metadata;
}
public M getMetadata() {
return this.metadata;
}
}
public static void main
(final String[] args
) { // The object whose GC lifecycle we want to track.
SampleObject<String> helloObject = new SampleObject<>("Hello");
// Reference queue that the phantom references will be registered to.
// They will be enqueued here when the appropriate reachability changes are detected by the JVM.
final ReferenceQueue<SampleObject<String>> refQueue = new ReferenceQueue<>();
// In this case, the metadata we associate with the object is some name.
final PhantomReferenceMetadata<SampleObject<String>, String> helloPhantomReference = new PhantomReferenceMetadata<>(
helloObject, refQueue, "helloObject");
System.
out.
println("Starting ReferenceQueue consumer thread."); final int numToDequeue = 1;
int numDequed = 0;
while (numDequed < numToDequeue) {
// Unfortunately, need to downcast to the appropriate type.
try {
@SuppressWarnings("unchecked")
final PhantomReferenceMetadata<SampleObject<String>, String> reference = (PhantomReferenceMetadata<SampleObject<String>, String>) refQueue
.remove();
// At this point, we know the object referred to by the PhantomReference has been finalized.
// So, we can do any other clean-up that might be allowed, such as cleaning up some temporary files
// associated with the object.
// The metadata stored in PhantomReferenceMetadata could be used to determine which temporary files
// should be cleaned up.
// You probably shouldn't rely on this as the ONLY method to clean up those temporary files, however.
System.
out.
println(reference.
getMetadata() + " has been finalized."); // Just for the purpose of this example.
break;
}
++numDequed;
}
System.
out.
println("Finished ReferenceQueue consumer thread."); }).start();
// Lose the strong reference to the object.
helloObject = null;
// Attempt to trigger a GC.
}
}