Java Reference Source Analysis

Keywords: Java Oracle

@(Java)[Reference]

Java Reference Source Analysis

Reference objects encapsulate references to other objects and can operate like normal objects, supporting interaction with garbage collectors under certain restrictions.You can use the Reference object to reference other objects, but it will eventually be recycled by the garbage collector.Programs sometimes need to be notified after object recycling to notify objects of changes in accessibility.
Java provides four different types of references, ranging in reference level from FinalReference, SoftReference, WeakReference, and PhantomReference.FinalReference is not available for external use.Each type corresponds to different levels of accessibility.

brief introduction

Strong reference FinalReference

Strong references refer to direct reachable references in a program without passing through any reference object, such as Object obj = new Object(); in which obj is a strong reference.

Soft Reference

Soft reference, not strong reference, but can be accessed through soft reference objects.Soft-referenced objects, the garbage collector will decide to recycle the object the soft reference points to only when memory is low (before throwing an OOM exception).Soft references are often used to implement memory-sensitive caching.

SoftReference<Object> softRef = new SoftReference<Object>(new Object());

WeakReference with weak reference

Weak reference, non-strong reference, and soft reference, but can be accessed through a weak reference object.Weakly referenced objects, whether memory is sufficient or not, are recycled whenever they are discovered by the garbage collector.For practical applications, see WeakHashMap, and so on.

WeakReference<Object> weakRef = new WeakReference<Object>(new Object());

Virtual Reference PhantomReference

A virtual reference, which must be used in conjunction with a reference queue, is typically used to track garbage collector recycling actions, such as calling the finalize method of an object when it is recycled. It is also safer to use a virtual reference to achieve this action.

Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
PhantomReference<Object> phantom = new PhantomReference<Object>(obj, refQueue);

ReferenceQueue

As a member of a reference, this queue can be used in combination with the three reference types mentioned above. The purpose of this queue is to register a Queue in the Reference when it is created, and to place the Reference in the queue when the object referenced by the Reference is recycled by the garbage collector, which is equivalent to a notification mechanism.
Example Demo1:

ReferenceQueue queue = new ReferenceQueue();

WeakReference reference = new WeakReference(new Object(), queue);
System.out.println(reference);
System.gc();

Reference reference1 = queue.remove();
System.out.println(reference1);

Source Code Analysis

Reference and ReferenceQueue

There are several more important properties inside the Reference

// Used to save references to objects, GC treats them specially according to different Reference s
private T referent;
// Saved queues if notification mechanism is required
ReferenceQueue<? super T> queue;
/* This is used to implement a one-way circular chain table to hold references that need to be processed by the ReferenceHandler */
Reference next;

static private class Lock { };
// Lock, used to synchronize the entry and exit of pending queues
private static Lock lock = new Lock();
// This property holds a PENDING queue for use with the next above
private static Reference pending = null;

state diagram

Internal class ReferenceHandler

ReferenceHandler is a static internal class of References that implements that Reference instances in the pending queue are added to different ReferenceQueue s in turn (depending on the queue inside the Reference).The pending element is joined by the GC.
Note: The pending queue is locked here because the GC thread may execute concurrently with the ReferenceHandler thread, such as when the GC is collected concurrently using CMS.
As shown in the following code

// This thread is started in a static block, that is, once a Reference is used, it will be started
private static class ReferenceHandler extends Thread {
    public void run() {
        for (;;) {

            Reference r;
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    Reference rn = r.next;
                    // Take the next element from pending, and if it is left blank, next points to itself pending = (rn == r)? Null: rn;
                    r.next = r;
                } else {
                    try {
                        // Wait if none, subsequent addition of elements will call lock.notify wake-up
                        lock.wait();
                    } catch (InterruptedException x) { }
                    continue;
                }
            }
            // ...
            ReferenceQueue q = r.queue;
            // If the Reference registers the corresponding Queue, it is added to the Queue
            if (q != ReferenceQueue.NULL) q.enqueue(r);
        }
    }
}

ReferenceQueue property

// Used to identify an unregistered Queue
static ReferenceQueue NULL = new Null();
// Used to identify that you are already in the corresponding Queue
static ReferenceQueue ENQUEUED = new Null();

static private class Lock { };
/* Mutex, used to synchronize enqueue of ReferenceHandler with remove and poll queue operations of user thread operations */
private Lock lock = new Lock();
// queue
private volatile Reference<? extends T> head = null;
// Number of elements in queue
private long queueLength = 0;

ReferenceQueue.enqueue

This method will only be called from the Reference to place the Reference in the current queue

boolean enqueue(Reference<? extends T> r) {
    synchronized (r) {
        // Determine if you are already in the team
        if (r.queue == ENQUEUED) return false;
        synchronized (lock) {
            r.queue = ENQUEUED;
            // One-way Cycle
            r.next = (head == null) ? r : head;
            head = r;
            queueLength++;
            if (r instanceof FinalReference) {
                sun.misc.VM.addFinalRefCount(1);
            }
            // Notify currently suspended threads (remove may be suspended when called)
            lock.notifyAll();
            return true;
        }
    }
}

ReferenceQueue.remove

public Reference<? extends T> remove(long timeout)
    throws IllegalArgumentException, InterruptedException
{
    if (timeout < 0) {
        throw new IllegalArgumentException("Negative timeout value");
    }
    synchronized (lock) {
        // Remove an element from the queue
        Reference<? extends T> r = reallyPoll();
        // If not empty, return directly
        if (r != null) return r;
        for (;;) {
            // Otherwise wait, notify wakes up when enqueue
            lock.wait(timeout);
            r = reallyPoll();
            if (r != null) return r;
            if (timeout != 0) return null;
        }
    }
}

Execution process

Use Demo1 as an example for analysis

// Create a reference queue
ReferenceQueue queue = new ReferenceQueue();

// Create a virtual reference, where the state is Active and Reference.pending is empty, the current Reference.queue = the queue created above, and next=null
WeakReference reference = new WeakReference(new Object(), queue);
System.out.println(reference);
// When GC executes, since it is a virtual reference, the object object is recycled and placed on pending, where the reference is in PENDING state
System.gc();

/* ReferenceHandler Remove the element from pending and place it in a queue, where the Reference state is ENQUEUED, and Reference.queue = Reference ENQUEUED */

/* When the element is removed from the queue, it becomes INACTIVE, Reference.queue = Reference.NULL */
Reference reference1 = queue.remove();
System.out.println(reference1);

Reference resources

Official documents:
http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html#package_description
Blog:
http://www.importnew.com/20468.html
http://hongjiang.info/java-referencequeue/
http://blog.csdn.net/lyfi01/article/details/6415726

Posted by not_skeletor on Wed, 17 Jul 2019 09:47:56 -0700