В ленте Twitter прочитал задачку про PhantomReference Я решил посмотреть, как используются фантомные ссылки в Одноклассниках. В приведенном коде я использую идею из кодовой базы проекта, но с добавлением собственных комментариев и багов, в силу скудоумия:

package ru.yamakarov.examples;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.ConcurrentHashMap;

public class Phantom {
    public static void main(String[] args) {
        test();
        System.gc();
    }

    private static void test() {
        // Ресурс, который мы хотим почистить, когда объект станет доступен только по фантомной ссылке
        String resource = "resource";
        // Объект использующий ресурс
        Garbage garbage = new Garbage(resource);

        new Cleaner(garbage) {

            @Override
            void clean() {
                System.out.println("Cleaned " + resource);
            }
        };

    }
}

// Класс освобождающий ресурсы после того, как использующий их объект стал недоступен
abstract class Cleaner extends  PhantomReference<Object> {

    // Очередь в которую попадают объекты требующие очистки
    private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
    // Храним ссылки, чтобы они не были собраны сборкой мусора
    private static ConcurrentHashMap<Cleaner, Cleaner> allCleaners = new ConcurrentHashMap<>();

    static {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Cleaner ref = (Cleaner) queue.remove();
                    allCleaners.remove(ref);
                    ref.clean();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        // Делаем поток демоном, так как он должен остановиться когда закончилось приложение
        thread.setDaemon(true);
        thread.start();
    }


    public Cleaner(Object referent) {
        super(referent, queue);
        allCleaners.put(this, this);
    }

    abstract void clean();

}


class Garbage {
    private final String resource;

    public Garbage(String resource) {
        this.resource = resource;
    }

    @Override
    public String toString() {
        return "Garbage{" +
                "resource='" + resource + '\'' +
                '}';
    }
}