codestory

Die Anleitung zu Java PhantomReference

  1. PhantomReference

1. PhantomReference

In diesem Artikel werden wir die Klasse PhantomReference besprechen. Bevor Sie beginnen, empfehle ich Ihnen, sich über die Klasse WeakReference und die Klasse SoftReference zu informieren. Alle drei Klassen haben die gleichen Grundeigenschaften und müssen nicht noch einmal erwähnt werden.
PhantomReference​ Constructors
PhantomReference​(T innerObject, ReferenceQueue<? super T> queue)
PhantomReference hat nur einen Konstruktor. Um ein Objekt PhantomReference zu erstellen, müssen Sie zwei Parameter angeben
  • innerObject: Das Objekt wird in das Objekt PhantomReference eingewickelt (wrapped)
  • queue:Eine Warteschlange, die zum Speichern dieses Objekt PhantomReference verwendet wird, wenn sein innerObject vom GC aus dem Speicher entfernt wird.
ReferenceQueue<AnyObject> queue = new ReferenceQueue<>();

AnyObject innerObject = new AnyObject("Obj1");

PhantomReference phantomRef = new PhantomReference(innerObject, queue);
Alle Methoden von PhantomReference werden von der Elternklasse geerbt.
// Methods inherited from parent.
public T get()  
public void clear()  
public boolean isEnqueued()  
public boolean enqueue()
Die Methode phantomReference.get() gibt immer null zurück. Der Zweck besteht darin, den Zugriff oder den Versuch, ein fast entferntes Objekt wiederzubeleben, zu verhindern.
Sie wundern sich vielleicht über die Eigenschaften von PhantomReference und fragen sich nun, wofür wird PhantomReference verwendet?
PhantomReference phantomRef = new PhantomReference(innerObject, queue);
Grundsätzlich können Sie mit PhantomReference genau bestimmen, wann das Objekt innerObject aus dem Speicher entfernt wird. Die Methode phantomRef.isEnqueued() gibt true zurück, was bedeutet, dass das Objekt innerObject aus dem Speicher entfernt wurde. Wenn das Objekt innerObject aus dem Speicher entfernt wird, wird das Objekt phantomRef in die queue gestellt.
Beispiel: Wenn Sie den Speicher für die Verarbeitung großer Videodateien zuweisen müssen, ist die Verwendung von PhantomReference eine gute Wahl. Verwenden Sie zunächst PhantomReference, um den Speicher für die Verarbeitung des ersten Videos zuzuweisen. Anschließend müssen Sie überprüfen, ob Speicher freigegeben wurde, bevor Sie mit der Speicherzuweisung für die Verarbeitung der nächsten Videodatei fortfahren. Dies verringert das Risiko, einen OutOfMemoryError zu erhalten.
Die Klasse VideoProcessor simuliert die Verarbeitung einer großen Videodatei:
VideoProcessor.java
package org.o7planning.phantomreference.ex;

public class VideoProcessor {
    private String video;

    public VideoProcessor(String video)  {
        this.video = video;
        System.out.println("\nNew VideoProcessor: " + this.video);
    }

    public void process() {
        System.out.println("   >>> Processing video: " + this.video);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) { }
        System.out.println("   >>> Completed processing video: " + this.video);
    }
    
    // !IMPORTANT: Do not override finalize() method.
    //  (Java9+: If you override this method, PhantomReference will not work!!)
    //    @Override
    //    protected void finalize() throws Throwable {
    //        System.out.println("VideoProcessor is being removed from memory\n");
    //        super.finalize();
    //    }
}
PhantomReferenceEx1.java
package org.o7planning.phantomreference.ex;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceEx1 {

    public static void main(String[] args) {

        String[] videos = new String[] { "video1.mp4", "video2.mp4", "video3.mp4" };

        ReferenceQueue<VideoProcessor> queue = new ReferenceQueue<VideoProcessor>();

        for (String video : videos) {
            VideoProcessor videoProcessor = new VideoProcessor(video);

            PhantomReference<VideoProcessor> phantomRef = new PhantomReference<>(videoProcessor, queue);
            videoProcessor.process();

            videoProcessor = null;
            // Call GC:
            System.gc();

            while (true) {
                boolean isEnqueued = phantomRef.isEnqueued();
                System.out.println(" phantomRef.isEnqueued: " + isEnqueued);
            
                if (!isEnqueued) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    continue;
                }
                break;
            }
        }
        System.out.println("\nObjects in the queue:");
        Reference<? extends VideoProcessor> ref= null;
        
        while((ref = queue.poll())!= null)  {
            System.out.println(ref);
        }
    }
}
Output:
New VideoProcessor: video1.mp4
   >>> Processing video: video1.mp4
   >>> Completed processing video: video1.mp4
 phantomRef.isEnqueued: false
 phantomRef.isEnqueued: true

New VideoProcessor: video2.mp4
   >>> Processing video: video2.mp4
   >>> Completed processing video: video2.mp4
 phantomRef.isEnqueued: false
 phantomRef.isEnqueued: true

New VideoProcessor: video3.mp4
   >>> Processing video: video3.mp4
   >>> Completed processing video: video3.mp4
 phantomRef.isEnqueued: false
 phantomRef.isEnqueued: true

Objects in the queue:
java.lang.ref.PhantomReference@5e265ba4
java.lang.ref.PhantomReference@156643d4
java.lang.ref.PhantomReference@123a439b

Java Grundlagen

Show More