前请先看《一提到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;
}});
}
}
}