引用队列ReferenceQueue
名字听起来是一个队列,实际使用了一个链表,使用头插法将加入的节点串起来,ReferenceQueue
中的head
变量指向链表的头节点,每个节点是一个Reference类型的对象:
public class ReferenceQueue<T> {// head为链表头节点private volatile Reference<? extends T> head = null;}
Reference
中除了discovered变量之外,还有一个next变量,discovered指向的是处于pending状态时pending列表中的下一个元素,next变量指向的是处于Enqueued状态时,引用队列中的下一个元素:
public abstract class Reference<T> {/* When active:处于active状态时为NULL*pending:this*Enqueued:Enqueued状态时,指向引用队列中的下一个元素*Inactive:this*/@SuppressWarnings("rawtypes")Reference next;/* When active:active状态时 , 指向GC维护的一个discovered链表中的下一个元素*pending:pending状态时,指向pending列表中的下一个元素*otherwise:其他情况为NULL*/transient private Reference<T> discovered;/* used by VM */}
文章插图
enqueue入队进入引用队列中的引用对象处于enqueue状态 。
enqueue
的处理逻辑如下:- 判断要加入的对象关联的引用队列,对队列进行判断 , 如果队列为空或者队列等于
ReferenceQueue
中的空队列ENQUEUED
,表示该对象之前已经加入过队列,不能重复操作,返回false,如果未加入过继续下一步; - 将对象所关联的引用队列置为
ENQUEUED
,它是一个空队列,表示节点已经加入到队列中; - 判断头节点是否为空,如果为空 , 表示链表还没有节点,将当前对象的next指向自己,如果头结点不为空,将当前对象的next指向头结点,然后更新头结点的值为当前对象(头插法插入链表);
- 增加队列的长度 , 也就是链表的长度;
public class ReferenceQueue<T> {// 空队列static ReferenceQueue<Object> ENQUEUED = new Null<>();// 入队,将节点加入引用队列,队列实际上是一个链表boolean enqueue(Reference<? extends T> r) {synchronized (lock) {// 获取关联的引用队列ReferenceQueue<?> queue = r.queue;// 如果为空或者已经添加到过队列if ((queue == NULL) || (queue == ENQUEUED)) {return false;}assert queue == this;// 将引用队列置为一个空队列,表示该节点已经入队r.queue = ENQUEUED;// 如果头结点为空将下一个节点置为自己,否则将next置为链表的头结点,可以看出同样使用的是头插法将节点插入链表r.next = (head == null) ? r : head;// 更新头结点为当前节点head = r;// 增加长度queueLength++;if (r instanceof FinalReference) {sun.misc.VM.addFinalRefCount(1);}lock.notifyAll();return true;}}}
poll出队在调用poll
方法从引用队列中获取一个元素并出队的时候,首先对head头结点进行判空,如果为空表示引用队列中没有数据,返回NULL,否则调用reallyPoll
从引用队列中获取元素 。出队的处理逻辑如下:
- 获取链表中的第一个节点也就是头结点,如果不为空进行下一步;
- 如果头节点的下一个节点是自己,表示链表只有一个节点,头结点出队之后链表为空,所以将头结点的值更新为NULL;
如果头节点的下一个节点不是自己 , 表示链表中还有其他节点,更新head头节点的值为下一个节点,也就是next指向的对象;
- 将需要出队的节点的引用队列置为NULL,next节点置为自己 , 表示节点已从队列中删除;
- 引用队列的长度减一;
- 返回要出队的节点;
public class ReferenceQueue<T> {/*** 从引用队列中获取一个节点,进行出队操作*/public Reference<? extends T> poll() {// 如果头结点为空 , 表示没有数据if (head == null)return null;synchronized (lock) {return reallyPoll();}}@SuppressWarnings("unchecked")private Reference<? extends T> reallyPoll() {、/* Must hold lock */// 获取头结点Reference<? extends T> r = head;if (r != null) {// 如果头结点的下一个节点是自己,表示链表只有一个节点,head置为null,否则head值为r的下一个节点,也就是next指向的对象head = (r.next == r) ?null :r.next;// 将引用队列置为NULLr.queue = NULL;// 下一个节点置为自己r.next = r;// 长度减一queueLength--;if (r instanceof FinalReference) {sun.misc.VM.addFinalRefCount(-1);}// 返回链表中的第一个节点return r;}return null;}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 怎么删除微信好友(一键恢复已删除好友)
- 浅谈-动态路由之OSPF的理解
- Jupyter,Matplotlib,Pandas 【机器学习】利用 Python 进行数据分析的环境配置 Windows
- 奇迹暖暖幽夜魅影怎么搭配
- 摩尔庄园10月28日神奇密码是多少
- 荣耀magic3支持鸿蒙系统吗_荣耀magic3能升级鸿蒙吗
- 可持久化数组 P3919 【模板】可持久化线段树 1
- 斗罗大陆武魂觉醒荒野行纪2
- 祖玛阁5去6怎么走(祖玛阁杂货店到6层怎么走)
- 【nginx】使用 nginx 时,使用 sub_filter 注入 js 代码,例如 google analysis 等