一、Reference简介
1.reference状态
Active:新创建的实例状态,当被垃圾收集器回收时,如果实例注册时候指定了队列,则变成Pending状态,否则变成Inactive状态。
Pending:pending-Reference列表的一个元素,等待被Reference-handler线程入队。解注册的实例不会是这种状态。
Enqueued:实例创建的时候指定的queue的一个元素,当实例从queue移除的时候,状态变成Inactive。解注册的实例不会是这种状态。
Inactive: 当一个实例的状态变成Inactive,它的状态永远不会改变。
2. 状态改变
如果初始化一个引用传入了ReferenceQueue,reference状态变化过程:Active->Pending->Enqueued->Inactive。如果没有传入ReferenceQueue,Active->Inactive。没有入队的过程。
3.简单举例
以弱引用举例,垃圾收集器工作,回收弱引用指向的对象(referent,referent状态变成finalizable)那一部分内存,由Reference-handler线程把pending状态的引用(reference)放入queue里面,然后把pending的discovered变成下一个pending。Reference-handler线程是一个高优先级的线程,并非是在垃圾回收器工作之后才去工作,而是一直等待着pending的值,有值就入队。以下为猜想,帮助更好理解:如果有四个弱引用r1、r2、r3、r4,没有被回收,状态都为Active,r1->discovered=r2,r2->discovered=r3,r3->discovered=r4,进行GC,Reference的静态变量pending值被GC赋值为r1,r1的状态变成Pending,Reference-handler线程检测到pending被赋值,把r1放入queue,r1状态变成Enqueued,然后把pending的值改为r1的成员变量discovered的值,即r2,r2的状态被变成Pending,重复这个过程,r1、r2、r3、r4依次进入queue,状态都变成Enqueued,而r4的discovered为空,pending又为空,等待GC赋值。
二、ReferenceQueue简介
1.ReferenceQueue名字叫队列,实际是个栈,按照后入先出的方式处理引用,后面还是称呼队。2.入队之后把引用内部的queue置为ENQUEUED,也就是一个空队列。如果引用的queue为空或者ENQUEUED则不处理。然后把当前引用的next指向之前的head,head指向当前引用。
3.出队就是把head弹出。出队有两种方法,一种head为空,一直等待。另一种是head为空,直接返回。
ReferenceQueue主要是用来追踪被GC掉的引用。比如WeakHashMap,把ReferenceQueue里面的引用key从Map里面删除。
如果引用从queue里面remove了,则状态变成Inactive。
三、Reference源码
public abstract class Reference<T> {
/* A Reference instance is in one of four possible internal states:
*
* Active: Subject to special treatment by the garbage collector. Some
* time after the collector detects that the reachability of the
* referent has changed to the appropriate state, it changes the
* instance's state to either Pending or Inactive, depending upon
* whether or not the instance was registered with a queue when it was
* created. In the former case it also adds the instance to the
* pending-Reference list. Newly-created instances are Active.
*
* Pending: An element of the pending-Reference list, waiting to be
* enqueued by the Reference-handler thread. Unregistered instances
* are never in this state.
*
* Enqueued: An element of the queue with which the instance was
* registered when it was created. When an instance is removed from
* its ReferenceQueue, it is made Inactive. Unregistered instances are
* never in this state.
*
* Inactive: Nothing more to do. Once an instance becomes Inactive its
* state will never change again.
*
* The state is encoded in the queue and next fields as follows:
*
* Active: queue = ReferenceQueue with which instance is registered, or
* ReferenceQueue.NULL if it was not registered with a queue; next =
* null.
*
* Pending: queue = ReferenceQueue with which instance is registered;
* next = this
*
* Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
* in queue, or this if at end of list.
*
* Inactive: queue = ReferenceQueue.NULL; next = this.
*
* With this scheme the collector need only examine the next field in order
* to determine whether a Reference instance requires special treatment: If
* the next field is null then the instance is active; if it is non-null,
* then the collector should treat the instance normally.
*
* To ensure that a concurrent collector can discover active Reference
* objects without interfering with application threads that may apply
* the enqueue() method to those objects, collectors should link
* discovered objects through the discovered field. The discovered
* field is also used for linking Reference objects in the pending list.
*/
private T referent; // 引用的具体对象,被垃圾收集器回收,值为null /* Treated specially by GC */
volatile ReferenceQueue<? super T> queue; // 初始化的时候被设置
/* When active: NULL
* pending: this
* Enqueued: next reference in queue (or this if last)
* Inactive: this
*/
@SuppressWarnings("rawtypes")
Reference next;
/* When active: next element in a discovered refer