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 {
    }
}
相關文章
相關標籤/搜索