Reference&ReferenceQueue源码解读

ReferenceQueue<T>

用来收集被 GC 后的对象(这个对象在这里是 会被 SoftReference、WeakReference、PhantomReference 包装的),这样的话,用户就可以在这个对象 GC 之后,做一些其它后续操作,比如 反向操作、数据清理等
下面是源码解读:

public class ReferenceQueue<T> {
    //构造方法 ,使用的时候,一般需要用户自己 new,自己保持这个 对象 
    public ReferenceQueue() { }
    //内部类 Null,这个 Null 重写了 enqueue 方法,就是不会把 GC 回收后的 引用对象(用户真实值是这个类的一个referent属性,此时这个属性已经被GC回收了) 存放到 这个 GC回收通知引用队列里面
    private static class Null<S> extends ReferenceQueue<S> {
        boolean enqueue(Reference<? extends S> r) {
            return false;
        }
    }
    //java 提供的 NULL 的 GC回收通知引用队列,(不会放入 GC回收通知引用队列)
    static ReferenceQueue<Object> NULL = new Null<>();
    //java 提供的 ENQUEUED 的 GC回收通知引用队列,(不会放入 GC回收通知引用队列)
    static ReferenceQueue<Object> ENQUEUED = new Null<>();
    //内部 锁 class
    static private class Lock { };
    //内部 锁 对象
    private Lock lock = new Lock();
    //存放GC回收后的 Reference 引用对象的 队列 的 head,需要和 Reference 对象的 next 属性配合使用
    private volatile Reference<? extends T> head = null;
    //队列长度
    private long queueLength = 0;
    
    //加入到 GC引用回收队列(此时用户的真正数据类已经被回收了);这个方法只会被 Reference 调用
    boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
        synchronized (lock) {
            // Check that since getting the lock this reference hasn't already been
            // enqueued (and even then removed)
            ReferenceQueue<?> queue = r.queue;//拿到对应的 回收队列
            if ((queue == NULL) || (queue == ENQUEUED)) {//如果是这2个java 内部回收队列,则返回 false
                return false;
            }
            assert queue == this;
            r.queue = ENQUEUED; //已经进入GC回收队列的话,这个queue就被置为 ENQUEUED(已入队模式)
            r.next = (head == null) ? r : head;
            head = r; //添加到队列头部
            queueLength++;  //队列长度+1
            if (r instanceof FinalReference) {  //这个就是 finalize 方法 的用处
                sun.misc.VM.addFinalRefCount(1);
            }
            lock.notifyAll();   //激活其它等待锁
            return true;    //返回true,表示 加入到了 GC引用回收队列
        }
    }
    
    //返回 引用队列 的 head
    private Reference<? extends T> reallyPoll() {       /* Must hold lock */
        Reference<? extends T> r = head;
        if (r != null) {
            head = (r.next == r) ?
                null :
                r.next; // Unchecked due to the next field having a raw type in Reference
            r.queue = NULL;
            r.next = r;
            queueLength--; //队列长度 -1
            if (r instanceof FinalReference) {
                sun.misc.VM.addFinalRefCount(-1);
            }
            return r;
        }
        return null;
    }
    
    //返回 引用队列 的 head;如果 GC回收通知引用队列 是null则快速返回null
    public Reference<? extends T> poll() {
        if (head == null)
            return null;
        synchronized (lock) {
            return reallyPoll();    //加锁使用 reallyPoll 获取
        }
    }
    
    //从 GC回收通知引用队列中 移除元素,没有元素 则会阻塞,(超时没有元素,则会返回null);用户在后处理 GC元素的时候使用
    public Reference<? extends T> remove(long timeout)
        throws IllegalArgumentException, InterruptedException
    {
        if (timeout < 0) {
            throw new IllegalArgumentException("Negative timeout value");
        }
        synchronized (lock) {
            Reference<? extends T> r = reallyPoll();    //使用reallyPoll获取 队列head元素
            if (r != null) return r;    //非空则直接返回
            long start = (timeout == 0) ? 0 : System.nanoTime();
            for (;;) {
                lock.wait(timeout); //null 则会等待
                r = reallyPoll();   //仔次获取
                if (r != null) return r;
                if (timeout != 0) { //如果设置了超时时间的话,超时没有元素,则会返回null
                    long end = System.nanoTime();
                    timeout -= (end - start) / 1000_000;
                    if (timeout <= 0) return null;
                    start = end;
                }
            }
        }
    }
    
    //从 GC回收通知引用队列中 移除元素,没有元素 则会阻塞;用户在后处理 GC元素的时候使用
    public Reference<? extends T> remove() throws InterruptedException {
        return remove(0);
    }
    
}

Reference 软、弱、虚 引用 的 父类

这个类及其子类 内部会存在一个 真正 存放 用户 真实值的属性 referent,当然 GC 回收的时候,也是回收的这个
真实值;
再配合不同的 ReferenceQueue 引用队列,就可以实现不同 GC 回收策略和回收后处理 策略。

public abstract class Reference<T> {
    private T referent; //真实的用户的值,Reference及其子类 都是 包装了这个真实的值,可以被GC清理;不同的子类GC清理的策略不同
    volatile ReferenceQueue<? super T> queue;   //GC回收通知引用队列
    Reference next; //链表结果; 存放 GC回收通知引用队列 数据
    
    //整个jvm中唯一,与discovered结合使用,pending 与 discovered构成了一个链表;这个链表就是pending-Reference链表
    //Garbage Collector 回收了referent对象后,会把相应的Reference对象放入pending-Reference链表中
    //pending-Reference链表: pending -> pending.discovered -> pending.discovered.discovered -> pending.discovered.discovered.discovered
    //Reference-handler线程 把 pending 入队到 ReferenceQueue,入队后 r = pending; pending = r.discovered; r.discovered = null;
    //进入pending-Reference链表,Reference对象需要满足两个条件
    //  1. Reference所引用的对象已经不存在其它强引用;
    //  2. Reference对象在创建的时候,指定了ReferenceQueue;
    private static Reference<Object> pending = null;
    transient private Reference<T> discovered;
    
    static private class Lock { } //内部锁class
    private static Lock lock = new Lock();  //内部锁实例
    
    //获取用户真实值方法,被GC清理后,就是 null 了
    public T get() {
        return this.referent;
    }
    //手动清理用户真实值方法
    public void clear() {
        this.referent = null;
    }
    //这个对象(里面的用户真实值)是否已经 进去到 GC回收通知引用队列了 (即是否已经被GC了)
    public boolean isEnqueued() {
        return (this.queue == ReferenceQueue.ENQUEUED);
    }
    //手动 把这个对象 加入到 GC回收通知引用队列
    public boolean enqueue() {
        return this.queue.enqueue(this);
    }
    
    //构造方法,不使用 GC回收通知引用队列
    Reference(T referent) {
        this(referent, null);
    }
    构造方法,使用 GC回收通知引用队列
    Reference(T referent, ReferenceQueue<? super T> queue) {
        this.referent = referent;
        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
    }
    
    //把 penging 的 对象 放入到对应的 GC回收通知吟咏队列里面去
    static boolean tryHandlePending(boolean waitForNotify) {
        Reference<Object> r;
        Cleaner c;
        try {
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    // 'instanceof' might throw OutOfMemoryError sometimes
                    // so do this before un-linking 'r' from the 'pending' chain...
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                    // unlink 'r' from 'pending' chain
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    if (waitForNotify) {
                        lock.wait();
                    }
                    // retry if waited
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
            // Give other threads CPU time so they hopefully drop some live references
            // and GC reclaims some space.
            // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
            // persistently throws OOME for some time...
            Thread.yield();
            // retry
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }

        // Fast path for cleaners
        if (c != null) {
            c.clean();
            return true;
        }

        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r); //入GC回收通知引用队列
        return true;
    }
    
    
    //内部 ReferenceHandler 类;Reference-handler线程
    private static class ReferenceHandler extends Thread {
        private static void ensureClassInitialized(Class<?> clazz) {
            try {
                Class.forName(clazz.getName(), true, clazz.getClassLoader());
            } catch (ClassNotFoundException e) {
                throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
            }
        }
        
        static {
            // pre-load and initialize InterruptedException and Cleaner classes
            // so that we don't get into trouble later in the run loop if there's
            // memory shortage while loading/initializing them lazily.
            ensureClassInitialized(InterruptedException.class);
            ensureClassInitialized(Cleaner.class);
        }
        //构造方法
        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }
        //线程方法
        public void run() {
            while (true) { //不停调用tryHandlePending,用于将pending-Reference链表的元素加入到ReferenceQueue
                tryHandlePending(true);
            }
        }
        
    }
    
    //类初始化 静态代码块 
    static {    //全局只会有一个 Reference-handler线程 
        ThreadGroup tg = Thread.currentThread().getThreadGroup(); //获取当前线程组
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent()); //直至找到 根线程组
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();    //启动 Reference-handler线程 

        // provide access in SharedSecrets
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }
    
}

强引用

只有没有任何饮用的时候,才可能被回收

SoftReference 软引用

只有当 jvm 内存不足的时候,才会回收这些只有软引用对象

public class SoftReference<T> extends Reference<T> {
    static private long clock;  //GC 垃圾回收才能更新它
    private long timestamp;     //get 方法会更新它
    
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }
    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }
    public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }
}

WeakReference 弱引用

只要 垃圾回收线程扫描它所在的区域,一旦发现 这个对象只有软引用时,就会回收

public class WeakReference<T> extends Reference<T> {
    public WeakReference(T referent) {
        super(referent);
    }
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

可以看到 WeakReference 就是 继承了 Reference,其它的没有做任何改变。

PhantomReference 虚引用

必须配合一个 ReferenceQueue 引用队列才能工作;一个对象如果只存在虚引用的话。那么任何时候都可能被回收
这种引用类型更关注的是 被垃圾回收器回收的活动。被回收时会收到⼀个系统通知。

public class PhantomReference<T> extends Reference<T> {
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
    public T get() {
        return null;
    }
}

可以看到 必须要传入一个 GC回收通知引用队列;并且获取 用户真实值一直是null

FinalReference 用来实现 finalization

class FinalReference<T> extends Reference<T> {
    public FinalReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

Finalizer

final class Finalizer extends FinalReference<Object> {
    private static ReferenceQueue<Object> queue = new ReferenceQueue<>();   //GC回收通知引用队列
    private static Finalizer unfinalized = null;    //没有被 finalizer 的 双向队列 header
    private Finalizer next = null, prev = null;     //没有被 finalizer 的 双向队列,向前、向后 值
    private static final Object lock = new Object(); //内部锁对象
    //增加元素到 unfinalized 双向队列里面
    private void add() {
        synchronized (lock) {
            if (unfinalized != null) {
                this.next = unfinalized;
                unfinalized.prev = this;
            }
            unfinalized = this;
        }
    }
    
    //构造方法是 private的,外部不能实例化
    private Finalizer(Object finalizee) {
        super(finalizee, queue);
        add();
    }
    //JVM 在类加载的时候,如果发现一个类重写了 finalize 方法的化,将会把这个类 注册到 unfinalized队列里面
    static void register(Object finalizee) {
        new Finalizer(finalizee);
    }
    //从 unfinalized 双向链表中移除第一个元素
    private void remove() {
        synchronized (lock) {
            if (unfinalized == this) {
                if (this.next != null) {
                    unfinalized = this.next;
                } else {
                    unfinalized = this.prev;
                }
            }
            if (this.next != null) {
                this.next.prev = this.prev;
            }
            if (this.prev != null) {
                this.prev.next = this.next;
            }
            this.next = this;   /* Indicates that this has been finalized */
            this.prev = this;
        }
    }
    //是否已经被remove了
    private boolean hasBeenFinalized() {
        return (next == this);
    }
    //执行 用户 类 的 finalize 方法
    private void runFinalizer(JavaLangAccess jla) {
        synchronized (this) {
            if (hasBeenFinalized()) return; //已经被remove了,那就什么也不做
            remove(); //从 unfinalized 双向链表中移除第一个元素
        }
        try {
            Object finalizee = this.get(); //获取 实际用户对象
            if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
                jla.invokeFinalize(finalizee);  //执行 实际用户对象 的 finalize 方法

                /* Clear stack slot containing this variable, to decrease
                   the chances of false retention with a conservative GC */
                finalizee = null;
            }
        } catch (Throwable x) { }   //忽略异常
        super.clear();  //实际用户对象 置null 
    }
    
    //内部 FinalizerThread 类
    private static class FinalizerThread extends Thread {
        private volatile boolean running; //running 标志
        //构造方法
        FinalizerThread(ThreadGroup g) {
            super(g, "Finalizer");
        }   
        
        //线程方法
        public void run() {
            if (running)
                return;

            // Finalizer thread starts before System.initializeSystemClass
            // is called.  Wait until JavaLangAccess is available
            while (!VM.isBooted()) {
                // delay until VM completes initialization
                try {
                    VM.awaitBooted();
                } catch (InterruptedException x) {
                    // ignore and continue
                }
            }
            final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
            running = true;
            for (;;) {
                try {
                    Finalizer f = (Finalizer)queue.remove();    //从 GC回收通知引用队列 不断获取 finalizer reference 元素
                    f.runFinalizer(jla);    //执行 finalizer reference 元素 的 runFinalizer 方法
                } catch (InterruptedException x) {
                    // ignore and continue
                }
            }
        }
    }
    
    //类静态代码块
    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());   //找到 根 线程组
        Thread finalizer = new FinalizerThread(tg); //启动 finalizerThread 线程
        finalizer.setPriority(Thread.MAX_PRIORITY - 2);
        finalizer.setDaemon(true);
        finalizer.start();
    }
    
    //执行一个 runnable 对象的 方法
    private static void forkSecondaryFinalizer(final Runnable proc) {
        AccessController.doPrivileged(
            new PrivilegedAction<Void>() {
                public Void run() {
                ThreadGroup tg = Thread.currentThread().getThreadGroup();
                for (ThreadGroup tgn = tg;
                     tgn != null;
                     tg = tgn, tgn = tg.getParent());
                Thread sft = new Thread(tg, proc, "Secondary finalizer");
                sft.start();
                try {
                    sft.join();
                } catch (InterruptedException x) {
                    /* Ignore */
                }
                return null;
                }});
    }
    
    /* Called by Runtime.runFinalization() */ 
    //通过 Runtime.runFinalization() 调用
    static void runFinalization() {
        if (!VM.isBooted()) {
            return;
        }

        forkSecondaryFinalizer(new Runnable() {
            private volatile boolean running;
            public void run() {
                if (running)
                    return;
                final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
                running = true;
                for (;;) {
                    Finalizer f = (Finalizer)queue.poll();
                    if (f == null) break;
                    f.runFinalizer(jla);
                }
            }
        });
    }

    /* Invoked by java.lang.Shutdown */
    //通过 java.lang.Shutdown 调用
    static void runAllFinalizers() {
        if (!VM.isBooted()) {
            return;
        }

        forkSecondaryFinalizer(new Runnable() {
            private volatile boolean running;
            public void run() {
                if (running)
                    return;
                final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
                running = true;
                for (;;) {
                    Finalizer f;
                    synchronized (lock) {
                        f = unfinalized;
                        if (f == null) break;
                        unfinalized = f.next;
                    }
                    f.runFinalizer(jla);
                }}});
    }
}

参考

https://blog.csdn.net/qq_43579103/article/details/108840706
https://blog.csdn.net/ctwy291314/article/details/85095750

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是ReferenceQueue源码分析: ReferenceQueue是一个抽象类,其定义如下: ``` public abstract class ReferenceQueue<T> { static ReferenceQueue<Object> NULL = new Null<>(); static class Null<T> extends ReferenceQueue<T> { @SuppressWarnings("unchecked") public Reference<? extends T> poll() { return null; } public Reference<? extends T> remove(long timeout) throws IllegalArgumentException { throw new IllegalArgumentException(); } public Reference<? extends T> remove() { return null; } } ... } ``` ReferenceQueue类中只定义了一个静态的内部类Null,同时该类中也没有任何实例变量和实例方法。Null类实现了ReferenceQueue抽象类,并重写了父类中的三个方法。这三个方法分别是: - poll():从队列中获取并移除一个引用对象,如果队列为空则返回null。 - remove(long timeout):从队列中获取并移除一个引用对象,如果队列为空则等待指定的时间,如果在指定的时间内队列仍为空则返回null。 - remove():从队列中获取并移除一个引用对象,如果队列为空则一直等待,直到队列非空。 在Java中,我们可以使用ReferenceQueue来监控一个对象是否被垃圾回收。当一个对象被垃圾回收时,与该对象关联的引用对象将会被加入到ReferenceQueue中。通过使用ReferenceQueue,我们可以在另一个线程中对被回收的对象进行处理,执行一些必要的清理工作或者记录日志等操作。 在使用ReferenceQueue时,我们需要将要被监控的引用对象与ReferenceQueue关联起来,一般使用弱引用、软引用或虚引用来实现。例如,我们可以使用如下代码将一个对象obj与一个ReferenceQueue关联起来: ``` ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); WeakReference<Object> weakReference = new WeakReference<>(obj, referenceQueue); ``` 在这个示例中,我们使用了一个WeakReference来关联obj对象和referenceQueue,当obj对象被垃圾回收时,与obj关联的弱引用将会被加入到referenceQueue中。我们可以在另一个线程中通过调用referenceQueue.poll()方法来获取被回收的弱引用对象,从而进行必要的清理工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值