betacode

Руководство Java PhantomReference

  1. PhantomReference

1. PhantomReference

В этой статье мы обсудим класс PhantomReference. Перед началом работы я рекомендую вам ознакомиться с классами WeakReference и SoftReference. Все эти три класса имеют одни и те же основные характеристики и не нуждаются в повторном упоминании.
PhantomReference​ Constructors
PhantomReference​(T innerObject, ReferenceQueue<? super T> queue)
PhantomReference имеет только один constructor. Чтобы создать объект PhantomReference, необходимо указать два параметра:
  • innerObject: Объект будет обернут внутри объекта PhantomReference.
  • queue: Очередь, используемая для хранения этого объекта PhantomReference, когда его объект innerObject удаляется из памяти by GC.
ReferenceQueue<AnyObject> queue = new ReferenceQueue<>();

AnyObject innerObject = new AnyObject("Obj1");

PhantomReference phantomRef = new PhantomReference(innerObject, queue);
Все методы of PhantomReference наследуются от родительского класса.
// Methods inherited from parent.
public T get()  
public void clear()  
public boolean isEnqueued()  
public boolean enqueue()
Метод PhantomReference.get() всегда возвращает null, цель которого - предотвратить доступ или попытку оживить объект, который почти был удален.
Возможно, вы задаетесь вопросом о характеристиках of PhantomReference, и теперь ваш вопрос заключается в том, для чего используется PhantomReference?
PhantomReference phantomRef = new PhantomReference(innerObject, queue);
В принципе, PhantomReference предоставляет вам возможность точно определить, когда его объект innerObject удаляется из памяти. Метод phantomRef.isEnqueued() возвращает true, что означает, что объект innerObject был удален из памяти. Когда объект innerObject удаляется из памяти, объект phantomRef будет помещен в очередь (queue).
Например: Если вам нужно выделить память для обработки больших видеофайлов, то использование PhantomReference - это хороший выбор. Сначала используйте PhantomReference для выделения памяти для обработки первого видео, затем вам нужно убедиться, что память была освобождена, прежде чем продолжать выделять память для обработки следующего видеофайла. Это уменьшает риск получения ошибки OutOfMemoryError.
Класс VideoProcessor имитирует обработку большого видеофайла:
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 Basic

Show More