• Guava Finalizer


    /*
     * Copyright (C) 2008 The Guava Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use
     * this file except in compliance with the License. You may obtain a copy of the License at
     * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
     * either express or implied. See the License for the specific language governing permissions and limitations under the
     * License.
     */
    
    package com.google.common.base.internal;
    
    import java.lang.ref.PhantomReference;
    import java.lang.ref.Reference;
    import java.lang.ref.ReferenceQueue;
    import java.lang.ref.WeakReference;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     * Thread that finalizes referents. All references should implement {@code com.google.common.base.FinalizableReference}.
     *
     * 用来清理被引用对象.所有的引用必须实现FinalizableReference
     *
     * <p>
     * While this class is public, we consider it to be *internal* and not part of our published API. It is public so we can
     * access it reflectively across class loaders in secure environments.
     *
     * 当这个类是public时,我们将其作为internal而非published的API.因为他是public的所以我们可以在一个安全的环境中通过class loaders反射地来访问他
     *
     * <p>
     * This class can't depend on other Google Collections code. If we were to load this class in the same class loader as
     * the rest of Google Collections, this thread would keep an indirect strong reference to the class loader and prevent
     * it from being garbage collected. This poses a problem for environments where you want to throw away the class loader.
     * For example, dynamically reloading a web application or unloading an OSGi bundle.
     *
     * 这个类不能依赖于其他Google Collections代码.假如我们像其他Google Collections那样在同一个class loader中载入这个类,这个线程会保留一个
     * 间接的强引用到class loader上并阻止他被垃圾回收.这会在当你想丢弃这个class loader的时候造成一个问题.例如,动态的重新载入一个web应用程序或者
     * 卸载一个osgi bundle
     *
     * <p>
     * {@code com.google.common.base.FinalizableReferenceQueue} loads this class in its own class loader. That way, this
     * class doesn't prevent the main class loader from getting garbage collected, and this class can detect when the main
     * class loader has been garbage collected and stop itself.
     *
     * FinalizableReferenceQueue使用它自己的class loader加载这个类,也就是说这个类不会阻止主class loader被垃圾回收,并且这个在检测到主
     * class loader被垃圾回收后会停止他自己
     */
    public class Finalizer implements Runnable {
    
        private static final Logger logger = Logger.getLogger(Finalizer.class.getName());
    
        /** Name of FinalizableReference.class. */
        private static final String FINALIZABLE_REFERENCE = "com.google.common.base.FinalizableReference";
    
        /**
         * Starts the Finalizer thread. FinalizableReferenceQueue calls this method reflectively.
         * 启动Finalizer线程,FinalizableReferenceQueue使用反射调用这个方法
         *
         * @param finalizableReferenceClass FinalizableReference.class
         * @param frq reference to instance of FinalizableReferenceQueue that started this thread
         * @return ReferenceQueue which Finalizer will poll
         */
        public static ReferenceQueue<Object> startFinalizer(Class<?> finalizableReferenceClass, Object frq) {
            /*
             * We use FinalizableReference.class for two things: 1) To invoke FinalizableReference.finalizeReferent() 2) To
             * detect when FinalizableReference's class loader has to be garbage collected, at which point, Finalizer can
             * stop running
             *
             * 我们使用FinalizableReference.class做两件事情
             * 1) 调用FinalizableReference.finalizeReferent()
             * 2) 检测FinalizableReference的class loader是否会被垃圾回收,此时Finalizer将会停止运行
             */
            if (!finalizableReferenceClass.getName().equals(FINALIZABLE_REFERENCE)) {
                throw new IllegalArgumentException("Expected " + FINALIZABLE_REFERENCE + ".");
            }
    
            // 启动一个Finalizer后台线程
            Finalizer finalizer = new Finalizer(finalizableReferenceClass, frq);
            Thread thread = new Thread(finalizer);
            thread.setName(Finalizer.class.getName());
            thread.setDaemon(true);
    
            try {
                if (inheritableThreadLocals != null) { // 将thread的inheritableThreadLocals设为null
                    inheritableThreadLocals.set(thread, null);
                }
            } catch (Throwable t) {
                logger.log(Level.INFO, "Failed to clear thread local values inherited" + " by reference finalizer thread.",
                        t);
            }
    
            thread.start();
            return finalizer.queue;
        }
    
        /** FinalizableReference的class的弱引用 */
        private final WeakReference<Class<?>> finalizableReferenceClassReference;
        /** FinalizableReferenceQueue的虚引用 */
        private final PhantomReference<Object> frqReference;
        /** ReferenceQueue */
        private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    
        private static final Field inheritableThreadLocals = getInheritableThreadLocalsField();
    
        /** Constructs a new finalizer thread. */
        private Finalizer(Class<?> finalizableReferenceClass, Object frq) {
            this.finalizableReferenceClassReference = new WeakReference<Class<?>>(finalizableReferenceClass);
    
            // Keep track of the FRQ that started us so we know when to stop.
            this.frqReference = new PhantomReference<Object>(frq, queue);
        }
    
        /**
         * Loops continuously, pulling references off the queue and cleaning them up.
         *
         * 不断循环并将queue里的reference出队做清理
         */
        @SuppressWarnings("InfiniteLoopStatement")
        @Override
        public void run() {
            try {
                while (true) {
                    try {
                        // remove()方法是一个死循环方法,直到返回Reference才会退出循环
                        cleanUp(queue.remove());
                    } catch (InterruptedException e) { /* ignore */
                    }
                }
            } catch (ShutDown shutDown) { /* ignore */
            }
        }
    
        /**
         * Cleans up a single reference. Catches and logs all throwables.
         *
         * 清理一个reference
         */
        private void cleanUp(Reference<?> reference) throws ShutDown {
            // 获取 finalizeReferent() 方法
            Method finalizeReferentMethod = getFinalizeReferentMethod();
            do {
                /*
                 * This is for the benefit of phantom references. Weak and soft references will have already been cleared by
                 * this point.
                 *
                 * 给虚引用使用的方法,如果是弱引用和软引用此时已经被cleared了
                 */
                // 将Reference内的referent清除
                reference.clear();
    
                if (reference == frqReference) {
                    /*
                     * The client no longer has a reference to the FinalizableReferenceQueue. We can stop.
                     *
                     * 当FinalizableReferenceQueue的reference自己被加入到了ReferenceQueue中时,停止Finalizer
                     */
                    throw new ShutDown();
                }
    
                try {
                    // 调用终结referent的方法
                    finalizeReferentMethod.invoke(reference);
                } catch (Throwable t) {
                    logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
                }
    
                /*
                 * Loop as long as we have references available so as not to waste CPU looking up the Method over and over
                 * again.
                 *
                 * 只要queue里还有reference就持续循环
                 */
                // poll()是一个无延迟方法,如果queue里没有对象,则直接返回null,这点与remove()不同
            } while ((reference = queue.poll()) != null);
        }
    
        /**
         * Looks up FinalizableReference.finalizeReferent() method.
         */
        private Method getFinalizeReferentMethod() throws ShutDown {
            // 通过class的引用获取class
            Class<?> finalizableReferenceClass = finalizableReferenceClassReference.get();
            if (finalizableReferenceClass == null) {
                /*
                 * FinalizableReference's class loader was reclaimed. While there's a chance that other finalizable
                 * references could be enqueued subsequently (at which point the class loader would be resurrected by virtue
                 * of us having a strong reference to it), we should pretty much just shut down and make sure we don't keep
                 * it alive any longer than necessary.
                 */
                throw new ShutDown();
            }
            try {
                return finalizableReferenceClass.getMethod("finalizeReferent");
            } catch (NoSuchMethodException e) {
                throw new AssertionError(e);
            }
        }
    
        public static Field getInheritableThreadLocalsField() {
            try {
                Field inheritableThreadLocals = Thread.class.getDeclaredField("inheritableThreadLocals");
                inheritableThreadLocals.setAccessible(true);
                return inheritableThreadLocals;
            } catch (Throwable t) {
                logger.log(Level.INFO, "Couldn't access Thread.inheritableThreadLocals."
                        + " Reference finalizer threads will inherit thread local" + " values.");
                return null;
            }
        }
    
        /** Indicates that it's time to shut down the Finalizer. */
        @SuppressWarnings("serial")
        // Never serialized or thrown out of this class.
        private static class ShutDown extends Exception {
        }
    }
  • 相关阅读:
    修改手机端radio 样式
    css ul li 左对齐,换行
    8- 类
    virtualbox虚拟机上网方式
    HTTP请求头详解
    出差总结-2017-11-24
    Some characters cannot be mapped using "GBK" ...
    tortoisesvn与eclipse-svn的删除操作区别
    sql
    setInterval方法, clearInterval
  • 原文地址:https://www.cnblogs.com/zemliu/p/3325817.html
Copyright © 2020-2023  润新知