这是我个人对源码的理解,也希望大家批评指正。Reference主要是负责内存的一个状态,当然它还和Java虚拟机,垃圾回收器打交道。Reference类首先把内存分为4种状态Active,Pending,Enqueued,Inactive,一般来说内存一开始被分配的状态都是Active,Pending大概是指快要被放进队列的对象,也就是马上要回收的对象,Enqueued就是对象的内存已经被回收了,我们已经把这个对象放入到一个队列中,方便以后我们查询某个对象是否被回收,Inactive就是最终的状态,不能再变为其它状态。在内存分配的时候我么可以选择给它传入一个队列参数,这个参数的类名叫作ReferenceQueue,当然也可以选择不传入,取决于构造函数。

Reference类源码

/* -- Constructors -- */

Reference(T referent) {

this(referent, null);

}

Reference(T referent, ReferenceQueue super T> queue) {

this.referent = referent;

this.queue = (queue == null) ? ReferenceQueue.NULL : queue;

}

Reference类里面有两个值得注意的成员变量

/* When active:   next element in a discovered reference list maintained by GC (or this if last)

*     pending:   next element in the pending list (or null if last)

*   otherwise:   NULL

*/

transient private Reference discovered;  /* used by VM */

从英文注释大致的意思是说discovered表示下一个要回收的对象,请注意,目前他不是正要回收的对象,正要回收的对象是后面要提到的pending 变量,并且这个是由垃圾回收器控制。

/* 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. The

* list uses the discovered field to link its elements.

*/

private static Reference pending = null;

pending这个变量表示它是下一个要进入ReferenceQueue队列的对象,并且它也是目前正要回收的对象。

我们从Reference源码中发现没有给discovered和pending 赋值的地方,也就是说pending和discovered很有可能是垃圾回收器给它们赋值。

这个队列ReferenceQueue到底有什么作用呢

查看ReferenceQueue的源码,发现这个类里面主要的的方法也就是2个

enqueue这个方法其实比较简单,首先是用lock这个锁实现同步,也就是在某个时间段只能有一个线程访问,后面的也就是把对象插入进去,新插进的元素在最上面,也就是头部。

ReferenceQueue类的源码

进队

boolean enqueue(Reference extends T> r) { /* Called only by Reference class */

synchronized (lock) {

// Check that since getting the lock this reference hasn't already been

// enqueued (and even then removed)

ReferenceQueue> queue = r.queue;

if ((queue == NULL) || (queue == ENQUEUED)) {

return false;

}

assert queue == this;

r.queue = ENQUEUED;

r.next = (head == null) ? r : head;

head = r;

queueLength++;

if (r instanceof FinalReference) {

sun.misc.VM.addFinalRefCount(1);

}

lock.notifyAll();

return true;

}

}

reallyPoll这个函数主要是从队列里面取出元素,表面上说是队列,个人感觉它就像栈,

出队

private Reference extends T> reallyPoll() {       /* Must hold lock */

Reference extends T> r = head;

if (r != null) {

head = (r.next == r) ?

null :

r.next; // Unchecked due to the next field having a raw type in Reference

r.queue = NULL;

r.next = r;

queueLength--;

if (r instanceof FinalReference) {

sun.misc.VM.addFinalRefCount(-1);

}

return r;

}

return null;

}

ReferenceQueue这个类有什么用呢,它跟Reference有什么关系呢,关系主要体现在这几个方面,首先Reference这个类里面在构造函数的时候有两种选择,一种是给它传入一个ReferenceQueue,一种是不传,如果不传的话,等这个对象的内存被回收了,直接从Active变为Inactive状态,如果我们传入了ReferenceQueue,那么当对象的内存回收的时候会经历一个过程,从Active->Pending->Enqueued->Inactive。pending状态就是等待着进入ReferenceQueue队列的这样一个状态,说白了它目前还没被回收,如果回收的话,回收结束后,会把该对象的引用放入到我们在构造函数时传入的那个队列里面,Enqueued就是说该对象已经被回收了,并且把该对象放入到了ReferenceQueue队列里面,当经历第三个状态的时候,和ReferenceQueue的关系很密切,

Reference类里面的源码,这部分源码的意思大概是开启一个后台线程,并且这个线程的优先级很高,一直负责循环回收内存,只要有内存可以回收,就马上回收,没有的话就 阻塞等待,但是值得注意的是ReferenceQueue q = r.queue;if (q != ReferenceQueue.NULL)

q.enqueue(r);这段代码,也就是说如果被回收对象里面的成员queue不为空,当它被回收时,我们就把它放入到队列里面,进入到前面提到的第三个状态,这个过程能发生,要有个条件,就是前面提到的,你必须在构造该对象时传一个队列参数给这个对象得成员queue。我们把这个对象放到队列里有什么用,当我们在用软引用的时候,可以去查询这个队列,来知道哪些对象已经被删除了,如果发现这个对象被删除了,我们可能会重新创建一个对象。

Reference类源码   ReferenceHandler 是Reference的一个内部类

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;

pending = r.discovered;

r.discovered = null;

} else {

try {

try {

lock.wait();

} catch (OutOfMemoryError x) { }

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

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

}

java referencequeue_java源代码 Reference和ReferenceQueue分析相关推荐

  1. Java源码:Reference与ReferenceQueue

    一:Reference与ReferenceQueue Reference的四种状态: Active:活跃,内存一开始分配的常有状态,垃圾收集器进行对该引用可达性分析后会进入Pending或Inacti ...

  2. java 源码系列 - 带你读懂 Reference 和 ReferenceQueue

    java 源码系列 - 带你读懂 Reference 和 ReferenceQueue https://blog.csdn.net/gdutxiaoxu/article/details/8073858 ...

  3. binder 从c到java_Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析...

    在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是 ...

  4. Reference和ReferenceQueue

    我们都知道在堆里面存放着Java中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还"存活"着,哪些已经"死去".那么gc怎 ...

  5. java 分析java死锁_Java死锁示例–如何分析死锁情况

    java 分析java死锁 死锁是两个线程或多个线程永远被阻塞的编程情况,这种情况发生在至少两个线程和两个或更多资源的情况下. 在这里,我编写了一个简单的程序,它将导致死锁情况,然后我们将看到如何对其 ...

  6. Java线程栈的获取和分析

    获取进程号 使用命令:jps 常用参数: -m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null. -l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径. -v 输出传 ...

  7. java中的Reference类型

    本文简要总结java中的Reference类型. 最近在研读jdk并发框架,其中AQS是重点,由于我打破砂锅问到底的轻微强迫症,google了AQS作者Doug Lea的论文原文[The java.u ...

  8. 《Java: The Complete Reference》等书读书笔记

    春节期间读了下<Java: The Complete Reference>发现这本书写的深入浅出,我想一个问题,书中很多内容我们也知道,但是为什么我们就写不出这样一本书,这么全面,这么系统 ...

  9. Java功底之Reference

    看了这篇文章,相信大家一定回对Java的参数传递熟练掌握,不会再对应用莫名其妙了. JAVA的参数传递,基本类型是把实参赋给形参, 对象是COPY一个副本堆栈里. 很多Java程序员只求追随新生的事物 ...

最新文章

  1. 别再用ls、cat命令了,这有一套全新升级版,简洁快速还易上手
  2. 保守的机器学习如何拯救日新月异的我们
  3. Python3身份运算符(比较对象是否相同)
  4. 浅谈iPhone和iPad开发中的图标设置
  5. ajax async
  6. 计算机英语第六单元,计算机专业英语第六版第十单元课后汉译英,We do use other forms....这个do...
  7. 鼠标图标怎么自定义_酷鱼魔鼠——给鼠标添加酷炫的特效
  8. Oracle使用rman备份数据库时出现cannot reclaim的错误
  9. java中while循环练习,java练习 七、循环语句 do……while循环语句
  10. win下实现Linux的tab自动补全
  11. linux输入过的命令行,LINUX中命令行的历史记录和编辑
  12. Java坦克大战代码
  13. 2021蓝桥杯省赛c++A
  14. 一种便携式导弹飞控系统外场实时仿真测试系统设计
  15. r语言boxcox异方差_R教程-15:线性回归中的异方差
  16. K线形态识别—三K线之卖出型三日K线组合
  17. Snapper 基本入门简介 - 快速浏览和监听
  18. 洛谷P3975 弦论
  19. 【Vue】Vue打包文件后需要添加版本号Version,来防止更新后的页面有缓存
  20. 股市几个常用基本面指标介绍

热门文章

  1. labelme实例分割_GitHub:图像分割最全资料集锦
  2. c#求三角形面积周长公式_C#源代码—三角形面积、圆的面积
  3. 企业级应用_浪潮NF8480M5,支撑新时代的企业级应用
  4. linux部署前后端分离项目命令笔记
  5. 无尽列表_8号无尽征途强势来袭,碎片商店列表更新,有136皮肤碎片的笑了
  6. android studio提示要重写的方法,Android Studio 重写方法时参数命名异常
  7. matlab求微分方程的系数,Matlab中系数为离散值的微分方程求解【编辑完成求解答】...
  8. Catalyst 5.8: the Perl MVC Framework
  9. 虚拟机Linux和宿主机传输文件
  10. AndroidO Treble架构下HIDL服务Java框架实现