java referencequeue_java源代码 Reference和ReferenceQueue分析
这是我个人对源码的理解,也希望大家批评指正。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分析相关推荐
- Java源码:Reference与ReferenceQueue
一:Reference与ReferenceQueue Reference的四种状态: Active:活跃,内存一开始分配的常有状态,垃圾收集器进行对该引用可达性分析后会进入Pending或Inacti ...
- java 源码系列 - 带你读懂 Reference 和 ReferenceQueue
java 源码系列 - 带你读懂 Reference 和 ReferenceQueue https://blog.csdn.net/gdutxiaoxu/article/details/8073858 ...
- binder 从c到java_Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析...
在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是 ...
- Reference和ReferenceQueue
我们都知道在堆里面存放着Java中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还"存活"着,哪些已经"死去".那么gc怎 ...
- java 分析java死锁_Java死锁示例–如何分析死锁情况
java 分析java死锁 死锁是两个线程或多个线程永远被阻塞的编程情况,这种情况发生在至少两个线程和两个或更多资源的情况下. 在这里,我编写了一个简单的程序,它将导致死锁情况,然后我们将看到如何对其 ...
- Java线程栈的获取和分析
获取进程号 使用命令:jps 常用参数: -m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null. -l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径. -v 输出传 ...
- java中的Reference类型
本文简要总结java中的Reference类型. 最近在研读jdk并发框架,其中AQS是重点,由于我打破砂锅问到底的轻微强迫症,google了AQS作者Doug Lea的论文原文[The java.u ...
- 《Java: The Complete Reference》等书读书笔记
春节期间读了下<Java: The Complete Reference>发现这本书写的深入浅出,我想一个问题,书中很多内容我们也知道,但是为什么我们就写不出这样一本书,这么全面,这么系统 ...
- Java功底之Reference
看了这篇文章,相信大家一定回对Java的参数传递熟练掌握,不会再对应用莫名其妙了. JAVA的参数传递,基本类型是把实参赋给形参, 对象是COPY一个副本堆栈里. 很多Java程序员只求追随新生的事物 ...
最新文章
- 别再用ls、cat命令了,这有一套全新升级版,简洁快速还易上手
- 保守的机器学习如何拯救日新月异的我们
- Python3身份运算符(比较对象是否相同)
- 浅谈iPhone和iPad开发中的图标设置
- ajax async
- 计算机英语第六单元,计算机专业英语第六版第十单元课后汉译英,We do use other forms....这个do...
- 鼠标图标怎么自定义_酷鱼魔鼠——给鼠标添加酷炫的特效
- Oracle使用rman备份数据库时出现cannot reclaim的错误
- java中while循环练习,java练习 七、循环语句 do……while循环语句
- win下实现Linux的tab自动补全
- linux输入过的命令行,LINUX中命令行的历史记录和编辑
- Java坦克大战代码
- 2021蓝桥杯省赛c++A
- 一种便携式导弹飞控系统外场实时仿真测试系统设计
- r语言boxcox异方差_R教程-15:线性回归中的异方差
- K线形态识别—三K线之卖出型三日K线组合
- Snapper 基本入门简介 - 快速浏览和监听
- 洛谷P3975 弦论
- 【Vue】Vue打包文件后需要添加版本号Version,来防止更新后的页面有缓存
- 股市几个常用基本面指标介绍
热门文章
- labelme实例分割_GitHub:图像分割最全资料集锦
- c#求三角形面积周长公式_C#源代码—三角形面积、圆的面积
- 企业级应用_浪潮NF8480M5,支撑新时代的企业级应用
- linux部署前后端分离项目命令笔记
- 无尽列表_8号无尽征途强势来袭,碎片商店列表更新,有136皮肤碎片的笑了
- android studio提示要重写的方法,Android Studio 重写方法时参数命名异常
- matlab求微分方程的系数,Matlab中系数为离散值的微分方程求解【编辑完成求解答】...
- Catalyst 5.8: the Perl MVC Framework
- 虚拟机Linux和宿主机传输文件
- AndroidO Treble架构下HIDL服务Java框架实现