fork download
  1. import java.lang.ref.PhantomReference;
  2. import java.lang.ref.ReferenceQueue;
  3.  
  4. /**
  5.  * @author Peter Chng
  6.  */
  7. class Ideone {
  8.  
  9. // Just so we have a non-primitive, non-interned object that will be GC'd.
  10. public static class SampleObject<T> {
  11. private final T value;
  12.  
  13. public SampleObject(final T value) {
  14. this.value = value;
  15. }
  16.  
  17. @Override
  18. public String toString() {
  19. return String.valueOf(this.value);
  20. }
  21. }
  22.  
  23. public static class PhantomReferenceMetadata<T, M> extends PhantomReference<T> {
  24. // Some metadata stored about the object that will be used during some cleanup actions.
  25. private final M metadata;
  26.  
  27. public PhantomReferenceMetadata(final T referent, final ReferenceQueue<? super T> q,
  28. final M metadata) {
  29. super(referent, q);
  30. this.metadata = metadata;
  31. }
  32.  
  33. public M getMetadata() {
  34. return this.metadata;
  35. }
  36. }
  37.  
  38. public static void main(final String[] args) {
  39. // The object whose GC lifecycle we want to track.
  40. SampleObject<String> helloObject = new SampleObject<>("Hello");
  41.  
  42. // Reference queue that the phantom references will be registered to.
  43. // They will be enqueued here when the appropriate reachability changes are detected by the JVM.
  44. final ReferenceQueue<SampleObject<String>> refQueue = new ReferenceQueue<>();
  45.  
  46. // In this case, the metadata we associate with the object is some name.
  47. final PhantomReferenceMetadata<SampleObject<String>, String> helloPhantomReference = new PhantomReferenceMetadata<>(
  48. helloObject, refQueue, "helloObject");
  49.  
  50. new Thread(() -> {
  51. System.out.println("Starting ReferenceQueue consumer thread.");
  52. final int numToDequeue = 1;
  53. int numDequed = 0;
  54. while (numDequed < numToDequeue) {
  55. // Unfortunately, need to downcast to the appropriate type.
  56. try {
  57. @SuppressWarnings("unchecked")
  58. final PhantomReferenceMetadata<SampleObject<String>, String> reference = (PhantomReferenceMetadata<SampleObject<String>, String>) refQueue
  59. .remove();
  60.  
  61. // At this point, we know the object referred to by the PhantomReference has been finalized.
  62. // So, we can do any other clean-up that might be allowed, such as cleaning up some temporary files
  63. // associated with the object.
  64. // The metadata stored in PhantomReferenceMetadata could be used to determine which temporary files
  65. // should be cleaned up.
  66. // You probably shouldn't rely on this as the ONLY method to clean up those temporary files, however.
  67. System.out.println(reference.getMetadata() + " has been finalized.");
  68. } catch (final InterruptedException e) {
  69. // Just for the purpose of this example.
  70. break;
  71. }
  72. ++numDequed;
  73. }
  74. System.out.println("Finished ReferenceQueue consumer thread.");
  75. }).start();
  76.  
  77. // Lose the strong reference to the object.
  78. helloObject = null;
  79.  
  80. // Attempt to trigger a GC.
  81. System.gc();
  82. }
  83. }
  84.  
Success #stdin #stdout 0.23s 33836KB
stdin
Standard input is empty
stdout
Starting ReferenceQueue consumer thread.
helloObject has been finalized.
Finished ReferenceQueue consumer thread.