sun.misc.Cleaner原始碼解析

朱清震發表於2018-02-01

前請先看《一提到Reference 99.99%的java程式設計師都懵逼了》,否則裡面的講解會看不懂!弄懂了Reference看下我寫的註釋就輕鬆明白Cleaner原理

Cleaner原始碼解析

 

/*

 * Copyright (c) 2003, 2013, Oracle and/or itsaffiliates. All rights reserved.

 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES ORTHIS FILE HEADER.

 *

 * This code is free software; you canredistribute it and/or modify it

 * under the terms of the GNU General PublicLicense version 2 only, as

 * published by the Free SoftwareFoundation.  Oracle designates this

 * particular file as subject to the "Classpath"exception as provided

 * by Oracle in the LICENSE file thataccompanied this code.

 *

 * This code is distributed in the hope that itwill be useful, but WITHOUT

 * ANY WARRANTY; without even the impliedwarranty of MERCHANTABILITY or

 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License

 * version 2 for more details (a copy isincluded in the LICENSE file that

 * accompanied this code).

 *

 * You should have received a copy of the GNUGeneral Public License version

 * 2 along with this work; if not, write to theFree Software Foundation,

 * Inc., 51 Franklin St, FifthFloor, Boston, MA 02110-1301 USA.

 *

 * Please contact Oracle, 500 Oracle Parkway,Redwood Shores, CA 94065 USA

 * or visit www.oracle.com if you needadditional information or have any

 * questions.

 */

 

packagesun.misc;

 

import java.lang.ref.*;

import java.security.AccessController;

import java.security.PrivilegedAction;

 

 

/**

 * General-purpose phantom-reference-based cleaners.

 *

 * <p> Cleaners are a lightweight and more robust alternativeto finalization.

 * They are lightweight because they are notcreated by the VM and thus do not

 * require a JNI upcall to be created,and because their cleanup code is

 * invoked directly by the reference-handler thread ratherthan by the

 * finalizer thread.  They are more robust because they use phantomreferences,

 * the weakest type of reference object,thereby avoiding the nasty ordering

 * problems inherent to finalization.

 *

 * <p> A cleaner tracks a referent object and encapsulates athunkof arbitrary

 * cleanup code.  Some time after the GC detects that acleaner's referent has

 * become phantom-reachable, the reference-handler thread willrun the cleaner.

 * Cleaners may also be invoked directly; theyare thread safe and ensure that

 * they run their thunks at most once.

 *

 * <p> Cleaners are not a replacement for finalization.  They should be used

 * only when the cleanup code is extremelysimple and straightforward.

 * Nontrivial cleaners are inadvisable sincethey risk blocking the

 * reference-handler thread and delaying further cleanupand finalization.

 *

 *

 * @author MarkReinhold

 */

//繼承自PhantomReference

publicclassCleaner

   extendsPhantomReference<Object>

{

 

   // Dummy reference queue, needed becausethe PhantomReference constructor

   // insists that we pass a queue.  Nothing will ever be placed on this queue

   // since the reference handler invokescleaners explicitly.

    //Cleaner引用的ReferenceQueue佇列,靜態全域性變數,如果你看過ReferenceHander執行緒的處理過程,就會知道,Cleaner物件經過ReferenceHander執行緒處理後是不會進入這個佇列的,設定它是為了讓Cleaner物件進入到pending佇列,能夠被ReferenceHander執行緒處理到,沒有設定佇列的Reference物件gc時會直接變為nactive狀態,不會進入pending佇列,詳情看我的另外一篇文章《一提到Reference 99.99%的java程式設計師都懵逼了》中關於Reference物件的狀態轉換

   privatestaticfinalReferenceQueue<Object>dummyQueue =newReferenceQueue<>();

 

   // Doubly-linked list of live cleaners,which prevents the cleaners

   // themselves from being GC'd before theirreferents

    // first變數與next、prev變數一起構建一個雙向連結串列, 我給它起了個名字叫unClean佇列,first是佇列的頭部,靜態變數,所以進入這個佇列的物件都不會被回收,Cleaner物件建立的時候會加入這個連結串列,回收之前會先從這個連結串列中被移除,出隊入隊操作都是在佇列頭部,所以太是一個後進先出佇列,unClean佇列的作用是保持對Cleaner物件的強引用,防止Cleaner物件在它引用的物件之前被垃圾回收器回收掉;

   staticprivate Cleanerfirst =null;

 

   privateCleaner

        next =null,

        prev =null;

  

   //unClean佇列入隊操作 ,加入到佇列頭部

  privatestaticsynchronized Cleaneradd(Cleanercl) {

        if (first !=null) {

            cl.next =first;

            first.prev =cl;

        }

        first =cl;

        returncl;

   }

    //unclean佇列的出隊操作,從頭部出隊

   privatestaticsynchronizedboolean remove(Cleaner cl) {

 

        // If already removed, do nothing

        if (cl.next==cl)

            returnfalse;

 

        // Update list

        if (first ==cl) {

            if (cl.next!=null)

                first =cl.next;

            else

                first =cl.prev;

        }

        if (cl.next!=null)

            cl.next.prev=cl.prev;

        if (cl.prev!=null)

            cl.prev.next=cl.next;

 

        // Indicate removal by pointing the cleaner to itself

        cl.next =cl;

        cl.prev =cl;

        returntrue;

 

   }

    //實現Runable介面的物件,這個物件會在實現的run方法裡做gc前清理資源的操作,它的run方法最終會由ReferenceHander執行緒來呼叫執行

   privatefinal Runnablethunk;

    //私有的構造方法,說明Cleaner物件是無法直接被建立的,引數為被引用的物件和ReferenceQueue成員變數

   privateCleaner(Objectreferent,Runnablethunk){

        super(referent,dummyQueue);

        this.thunk =thunk;

   }

   

    //這個create靜態方法提供給我們來例項化Cleaner物件,需要兩個引數,被引用的物件與實現了Runnable介面的物件,新建立的Cleaner物件被加入到了unclean佇列裡

   /**

     * Creates a new cleaner.

     *

     * @param  obthe referent object to be cleaned

     * @param thunk

     *        The cleanup code to be run when the cleaner is invoked.  The

     *        cleanup code is run directly from the reference-handler thread,

     *        so it should be as simple and straightforward as possible.

     *

     * @return The new cleaner

     */

   publicstatic Cleaner create(Objectob, Runnable thunk) {

        if (thunk ==null)

            returnnull;

        returnadd(new Cleaner(ob,thunk));

   }

    //clean方法先將物件從unclean佇列移除(這樣Cleaner物件就可以被gc回收掉了),然後呼叫thunk的run方法執行清理操作

   /**

     * Runs this cleaner, if it has not beenrun before.

     */

   publicvoid clean() {

        if (!remove(this))

            return;

        try {

            thunk.run();

        } catch (final Throwablex) {

            AccessController.doPrivileged(newPrivilegedAction<Void>() {

                    public Void run() {

                        if (System.err != null)

                            new Error("Cleaner terminated abnormally",x)

                               .printStackTrace();

                        System.exit(1);

                        returnnull;

                    }});

        }

   }

 

}


相關文章