从WeakLogHandler应用看Java的引用、引用队列

题记:

前几天讨论到WeakHashMap(这个是个弱引用的Map,用于缓存,弱引用的特点是随时被GC回收),WHM在每次put()会间接地调用expungeStaleEntries()来从去除实体。今天看到Hudon的WeakLogHandler的应用就怀着学习的目的来看看WeakRefence。(软引用在内存不足的时候被GC回收,弱引用可能在每次都被GC回收,她们的机制或原理是什么呢?我总是很好奇)

 

 

分析:

粗略看了下设计,有很多疑点不懂:

1、pending对象的用处?

2、ReferenceHandler线程什么时候notify呢?

3、到底哪些对象会被GC回收呢?

 

查了点资料后:http://www.ibm.com/developerworks/cn/java/i-garbage2/index.html

才有了点领悟。

 

“在 Java 1.2.2 中,整个引用处理发生很大的改变。其目标是平等地对待所有的引用,并以相同的方式处理它们。因此,我们实际上在堆上创建两个单独的对象 —— 对象本身和一个单独的 “引用” 对象。可选地,引用对象可以与一个队列相关联,当 referent 变得不可获得时,可以将引用对象添加到该队列中。”

 

所有引用都有个“引用队列”,也就是代码里的queue,ReferenceHandler 线程负责把reference入队列,如果未“标记”或者该引用没有指向任何Queue,则等待GC回收。

 

这里所谓的“标记”是指GC的标记阶段,也就是GC标记所有活动的对象,从效率上考虑,GC不会去标记unreachable的对象,而未“标记”的对象就是“垃圾”了。

 

所以作为WeakReference引用就不会被“标记”(register),从而会被GC回收掉,这点与Soft引用不同,Soft引用被标记但在内存不足的情况下,被特殊处理。

 

 

有分析不正确的地方,还请指正,也是处于学习阶段:)

 

 

 

弱引用Logger例子:

public final class WeakLogHandler extends Handler {
    private final WeakReference<Handler> target;
    private final Logger logger; // Logger的管理对象
   public WeakLogHandler(Handler target, Logger logger) {// 典型的把管理对象传入
        this.logger = logger;
        logger.addHandler(this);// 把干活对象加入管理对象中。
        this.target = new WeakReference<Handler>(target); // 新建弱引用,且未指定queue
    }
    public void publish(LogRecord record) {
        Handler t = resolve();
        if(t!=null)
            t.publish(record);
    }
    public void flush() {
        Handler t = resolve();
        if(t!=null)
            t.flush();
    }
    public void close() throws SecurityException {
        Handler t = resolve();
        if(t!=null)
            t.close();
    }
    private Handler resolve() { 
        Handler r = target.get(); // get引用,判断是否已经被回收
        if(r==null)
            logger.removeHandler(this);
        return r;
    }
    @Override
    public void setFormatter(Formatter newFormatter) throws SecurityException {
        super.setFormatter(newFormatter);
        Handler t = resolve();
        if(t!=null)
            t.setFormatter(newFormatter);
    }
    }

 

 

看看小兵WeakRefence的定义:

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

看到基本共享父类Reference。(莫非JAVA引用默认就是弱引用?) 

 

看看Reference类定义:

public abstract class Reference<T> {

    private T referent;		/* Treated specially by GC */
    ReferenceQueue<? super T> queue;  // 从后面分析来看,这个就是引用队列了,被标记的引用入队列
   Reference next; // 指向下一个引用
   transient private Reference<T> discovered; 	/* used by VM */

    /* Object used to synchronize with the garbage collector.  The collector
     * must acquire this lock at the beginning of each collection cycle.  It is
     * therefore critical that any code holding this lock complete as quickly
     * as possible, allocate no new objects, and avoid calling user code.
     */
    static private class Lock { };
    private static Lock lock = new Lock(); // GC线程在回收的时候的锁。

    /* List of References waiting to be enqueued.  The collector adds
     * References to this list, while the Reference-handler thread removes
     * them.  This list is protected by the above lock object.
     */
    private static Reference pending = null; 
 /* -- Constructors -- */

    Reference(T referent) {
	this(referent, null);
    }

    Reference(T referent, ReferenceQueue<? super T> queue) {
	this.referent = referent;
	this.queue = (queue == null) ? ReferenceQueue.NULL : queue;// 弱引用就是一个NULL的引用队列
    }
    /* High-priority thread to enqueue pending References
     */
    private static class ReferenceHandler extends Thread {// 注意这里是static线程,且优先级最高。
	ReferenceHandler(ThreadGroup g, String name) {
	    super(g, name);
	}
	public void run() {
	    for (;;) {

		Reference r;
		synchronized (lock) {
		    if (pending != null) {
			r = pending;
			Reference rn = r.next;
			pending = (rn == r) ? null : rn;
			r.next = r;
		    } else {
			try {
			    lock.wait();
			} catch (InterruptedException x) { }
			continue;
		    }
		}
		// Fast path for cleaners
		if (r instanceof Cleaner) {
		    ((Cleaner)r).clean();
		    continue;
		}
		ReferenceQueue q = r.queue;
		if (q != ReferenceQueue.NULL) q.enqueue(r); // 构造函数里面未指定queue,则指向NULL queue
	    }
	}
    }
    static {
	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();
    }

    /* -- Referent accessor and setters -- */

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>. 如果引用被程序或GC回收,则返回null
     */
    public T get() {
	return this.referent;
    }
    /**
     * Clears this reference object.  Invoking this method will not cause this
     * object to be enqueued.
     */
    public void clear() {
	this.referent = null;
    }
    /* -- Queue operations -- */

    /**
     * Tells whether or not this reference object has been enqueued, either by
     * the program or by the garbage collector.	 If this reference object was
     * not registered with a queue when it was created, then this method will
     * always return <code>false</code>.
     * 当前引用是否被程序或者GC入队列,如果创建的时候未注册,则返回false
     */
    public boolean isEnqueued() {
	/* In terms of the internal states, this predicate actually tests
	   whether the instance is either Pending or Enqueued */
	synchronized (this) {
	    return (this.queue != ReferenceQueue.NULL) && (this.next != null);
	}
    }
    /**
     * Adds this reference object to the queue with which it is registered,
     * if any.
     */
    public boolean enqueue() {
	return this.queue.enqueue(this);
    }
    /* -- Constructors -- */

    Reference(T referent) {
	this(referent, null);
    }
    Reference(T referent, ReferenceQueue<? super T> queue) {
	this.referent = referent;
	this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
    }
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值