java.lang.ref.Reference<T>

//看之前先要知道java里面的四种引用。package com.zby.ref;

import sun.misc.Cleaner;

/**
 * 引用对象的抽象基础类。这个类定义了所有引用对象的公共操作。因为引用对象在跟垃圾收集器紧密合作中被实现,所以这个类不能被引用对象直接继承。
 *
 * @author zhoubaiyun
 *
 * @param <T>
 */
public abstract class Reference<T> {
    /*
     * 一个引用实例是在这四个可能的内部状态之一。
     *
     * 活跃状态:服从于垃圾处理器的特别处理。有时在收集器检测到可达到的引用对象已经改变成为适当的状态,收集器改变实例的状态为挂起或者不活跃,
     * 依赖于是否这个实例在它创建时是否注册。在之前的情况收集器还会添加实例到挂起引用列表。 最新创建的实例使活跃状态。
     *
     * 挂起状态: 一个挂起引用列表中等待被引用处理线程排队的元素。没有注册的实例不可能有这个状态。
     *
     * 排队状态:一个队列里面的在创建时就被注册的实例元素。当一个实例被从他自己的引用队列移除,他就变成不活跃状态了。没有注册的实例不可能有这个状态。
     *
     * 不活跃状态:无所事事。一个实例变成不活跃状态就不可能再改变状态了。
     *
     * 状态像下面这样被编码到queue和next字段:
     *
     * 活跃:实例注册时queue = ReferenceQueue或者如果实例没有被注册queue=ReferenceQueue.NULL;next=null.
     *
     * 挂起:实例注册时queue = ReferenceQueue;next=queue里面的下一个实例,如果实例是队列最后一个元素,next=this
     *
     * 排队:queue = ReferenceQueue.ENQUEUED;next=queue里面的下一个实例,如果实例是队列最后一个元素,next=this
     *
     * 不活跃:queue = ReferenceQueue.NULL; next = this.
     *
     * 有了这些约束,收集器为了确定一个引用对象是否需要特别对待只需要检查next字段:如果next字段是null这个实例就是活跃的;如果
     * 不为null,这收集器就应该正常对待这个实例了。
     *
     * 为了保证并发收集器能发现活跃引用对象而不干涉可能在这些对象上调用queue()方法的应用线程,收集器应该通过已发现的字段链接已发现的对象。
     */
    private T referent;         //GC要特殊对待的对象
    ReferenceQueue<? super T> queue;

    Reference next;

    private transient Reference<T> discovered;  //VM使用

    //对象过去常常是跟垃圾收集器同步的。收集器在每一个收集周期开始时必须获取这个锁。
    //因此至关重要的是任何持有这个锁的代码必须尽快完成,不分配新对象,避免调用用户代码。
    private static class Lock { };

    private static Lock lock = new Lock();

    //等待排队的引用列表。当引用处理器线程移除引用,收集器就他们加到这个列表。这个列表被上面的锁对象保护。
    private static Reference pending = null;

    //排队挂起引用的高优先级线程
    private static class ReferenceHandler extends Thread {

        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);
            }
        }
    }

    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        //这个就是取最上层的线程组,看起来写的很溜
        //主线程有一个main线程组[Thread[main,5,main], null, null, null]
        //上面还有一个system线程组[Thread[Reference Handler,10,system], Thread[Finalizer,8,system], Thread[Signal Dispatcher,9,system], Thread[Attach Listener,5,system]]。
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());

        //启动一个引用处理线程
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        //如果还有系统独有的优先级比MAX_PRIORITY这个高,那么就高的
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();
    }

    /*GC要特殊对待的对象的访问器和设置器*/
    /**
     * 返回当前引用对象的GC要特殊对待的对象,不管这个对象已经被程序还是垃圾收集器清理了都返回null
     * @return
     */
    public T get() {
        return this.referent;
    }

    /**
     * 清理这个引用对象,执行这个方法不会引起对象进入排队队列。
     *
     * 这个方法只会被java代码执行;当垃圾收集器执行清理会很直接,不会执行这个方法。
     */
    public void clear() {
        this.referent = null;
    }

    /*查询操作*/
    /**
     * 告诉你这个引用对象是否一家被加入排队队列,不管是程序或者垃圾收集器干的。如果这个引用对象在创建时没有被注册到队列,这个方法会返回false。
     * @return
     */
    public boolean isEnqueued() {
        //在内部状态中可以看出来,这个方法实际上不管实例是挂起还是排队都会检查到
        synchronized (this) {
            return (this.queue != ReferenceQueue.NULL) && (this.next != null);
        }
    }
    /**
     * 添加这个引用对象到它注册到的任何队列里面。
     * 这个方法只会被java代码执行;当垃圾收集器执行清理会很直接,不会执行这个方法。
     * @return 如果这个引用对象被成功加入排队队列返回true,如果它已经被加入了排队队列或者在创建时没有注册到一个队列返回false。
     */
    public boolean enqueue() {
        return this.queue.enqueue(this);
    }

    /*构造方法*/
    Reference(T referent) {
        this(referent, null);
    }

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

看完后就明白了一个问题,JVM运行的时候至少开启几个线程?

时间: 2024-10-05 05:07:15

java.lang.ref.Reference<T>的相关文章

深入探讨 java.lang.ref 包--转

概述 Java.lang.ref 是 Java 类库中比较特殊的一个包,它提供了与 Java 垃圾回收器密切相关的引用类.这些引用类对象可以指向其它对象,但它们不同于一般的引用,因为它们的存在并不防碍 Java 垃圾回收器对它们所指向的对象进行回收.其好处就在于使者可以保持对使用对象的引用,同时 JVM 依然可以在内存不够用的时候对使用对象进行回收.因此这个包在用来实现与缓存相关的应用时特别有用.同时该包也提供了在对象的“可达”性发生改变时,进行提醒的机制.本文通过对该包进行由浅入深的介绍与分析

java.lang.Thread

package java.lang; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; impor

java.lang包

作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.特性——不用import 2.String String x = "abc"; <=> String x= new String("abc"); 因为public final class java.lang.String; 而String x="The number " + y;中,在JAVA中不管是什么变量或者对象,在对String进行加和时

java中的Reference抽象类

一.概述 位于java.lang.ref包下,声明:public abstract class Reference<T> extends Object 引用对象的抽象基类.此类定义了常用于所有引用对象的操作.因为引用对象是通过与垃圾回收器的密切合作来实现的,所以不能直接为此类创建子类. 二.方法详细 1.public T get()  返回此引用对象的指示对象.如果此引用对象已经由程序或垃圾回收器清除,则此方法将返回 null. 2.public void clear()  清除此引用对象.调

java中的Reference

这两天又重新学习了一下Reference,根据网上的资源做了汇总. Java中的引用主要有4种: 强引用 StrongReference: Object obj = new Object(); obj就为一个强引用,obj=null后, 该对象可能会被JVM回收 软引用 SoftReference: 在内存不够用的时候,才会回收软引用的对象. Object obj = new Object(); SoftReference<Object> softref = new SoftReference

应用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space)

http://www.educity.cn/wenda/351088.html 使用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space) 都说内存泄漏是C++的通病,内存溢出是Java的硬伤,这个头疼的问题算是让我给碰到了.我在做的这个功能涉及到修改word文档,因为微软没有公开word源代码,所以直接用java流来读取word的后果是读出来的会是乱码,经过查资料得知可以使用poi和jacob来操作word,jacob使用

JDK框架简析--java.lang包中的基础类库、基础数据类型

题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说.还是在一个层级上,它们都是须要被编译成字节码.在JRE中执行的,JDK编译后的结果就是jre/lib下的rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列全部文章基于的JDK版本号都是1.7.16. 源代码下载地址:https://jdk7.jav

jdk研究——java.lang

jdk研究 volatile 是什么意思? 如何看jdk源码? 如何调试源码!---------仔细解读关键类,关键代码,常用的api的解释! 自己有疑问的不懂地方-------- 不懂的太多怎么办.... 求分享求带求讲解原理啊! 有老师还是比没有好得多! 关键代码.难懂代码是哪些啊! 承上启下 结构图?流水图? 哪些又是胶水代码呢.辅助代码 PACKAGE java.lang Object System 大量出现类似:SecurityManager sm = getSecurityManag

java.lang.System

System类构造函数由private修饰,不可以被实例化,加载时调用static代码块. System类提供了标准输入输出流,错误输出流:其中out和err的类型是PrintStream /** * The <code>System</code> class contains several useful class fields * and methods. It cannot be instantiated. * * <p>Among the facilities