
描述
引用队列,在Reference类中辅助Reference的实现,对于注册ReferenceQueue的Reference对象,gc检测到可达性更改后,会将其加入到其中。
实现过程
构造方法
比较空洞的构造方法。。。。
1 |
public () { } |
内部类
Null
用于辅助表示ReferenceQueue对应Reference的状况,通过继承ReferenceQueue实现,覆盖原有的enqueue入队方法,使其始终返回false。
1 |
private static class Null<S> extends <S> { |
对应在ReferenceQueue中有两个静态变量NULL,ENQUEUED。
1 |
static ReferenceQueue<Object> NULL = new Null<>(); |
NULL表示没有注册ReferenceQueue的状态,ENQUEUED表示对应的Reference已经入队了。之后的逻辑操作中会以此来区分。
Lock
同Reference中的使用一样,使用一个空的Object类来实现同步。
1 |
static private class Lock { }; |
队列
在Reference得分析中我们看到了next引用变量,这一变量用于描述结点指向的下一个元素,除此之外,ReferenceQueue中还有一个head变量来指明队列的首部,queueLength变量指明队列长度。
1 |
Reference next; |
1 |
private volatile Reference<? extends T> head = null;//在ReferenceQueue中默认为null |
入队
入队操作是由enqueue函数实现的。传入的是一个Reference,而且该函数必须由对应注册ReferenceQueue的Reference才能调用。
1 |
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ |
首先,通过传入的Reference获取对应的ReferenceQueue,存储在queue即自身this。通过判断queue的参数是否标记为NULL(没有注册ReferenceQueue),ENQUEUED(注册了但是对应的Reference已经在队里了),排除这些后将其返回false,入队操作失败。剩下的使用断言语句保证Reference中的ReferenceQueue与自身类的对应关系。这些是准备工作。
入队过程开始,先将queue标记为ENQUEUED防止重复入队。接着判断之前是否含有入队元素,如果有就将其放到传入的Reference的后面(next),并重新设置传入的Reference为队头,如果之前的队为空队列则将传入的Reference的next指向自身。最后如果传入的Reference是FinalReference的话,就使用addFinalRefCount使计数加一,便于jvm处理。一切完成后通知等待入队的进程并返回入队成功。
出队
出队操作是由reallyPoll函数实现的。
1 |
("unchecked") |
也很简单的操作,先判断出队的对象不为空,也就是队首,判断出队后队中是否还有其他的元素,如果没有(出队的Reference中next指向自己)就将head置空,如果有就将head指向出队的Reference的next,之后清除出队Reference的引用队列,将其next指向自身,数量减一,判断出队的Reference是否为FinalReference,如果是就将对应的计数减一。返回出队的Reference。将出队方法封装:
1 |
public Reference<? extends T> poll() { |
移除
这一方法从队列中移除一个Reference。当队列为空时就等待一段时间直到移除一个Reference或者超时。timeout为超时时间。
1 |
public Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException { |
首先进行出队操作,如果出队不为空则完成移除,若队空则根据超时时间来判断设定起始时间(纳秒),之后循环进行,交出锁并等待,之后进行出队,判断使是否出队成功,根据超时时间判断是否超时,如果超时就返回null。
除此之外还有一个默认超时为0的函数,超时设为0即没有超时限制,直到从队列中获取一个移除的Reference对象。
1 |
public Reference<? extends T> remove() throws InterruptedException { |
小结
ReferenceQueue的实现很简单,就是一个队列的维护和相关的同步操作,但是其在Reference的使用中十分重要。充分理解ReferenceQueue有利于我们对Reference的理解。




近期评论