一、Reference——强、软、若、虚、终结器引用的共同父类
public abstract class Reference<T> {
private T referent; /* Treated specially by GC */
volatile ReferenceQueue<? super T> queue;
@SuppressWarnings("rawtypes")
volatile Reference next;
private transient Reference<?> discovered;
private static class ReferenceHandler extends Thread {
private static void ensureClassInitialized(Class<?> clazz) {
try {
Class.forName(clazz.getName(), true, clazz.getClassLoader());
} catch (ClassNotFoundException e) {
throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
}
}
static {
ensureClassInitialized(Cleaner.class);
}
ReferenceHandler(ThreadGroup g, String name) {
super(g, null, name, 0, false);
}
public void run() {
while (true) {
processPendingReferences();
}
}
}
/*
* Atomically get and clear (set to null) the VM's pending-Reference list.
*/
private static native Reference<?> getAndClearReferencePendingList();
/*
* Test whether the VM's pending-Reference list contains any entries.
*/
private static native boolean hasReferencePendingList();
/*
* Wait until the VM's pending-Reference list may be non-null.
*/
private static native void waitForReferencePendingList();
/*
* Enqueue a Reference taken from the pending list. Calling this method
* takes us from the Reference<?> domain of the pending list elements to
* having a Reference<T> with a correspondingly typed queue.
*/
private void enqueueFromPending() {
var q = queue;
if (q != ReferenceQueue.NULL) q.enqueue(this);
}
private static final Object processPendingLock = new Object();
private static boolean processPendingActive = false;
private static void processPendingReferences() {
// Only the singleton reference processing thread calls
// waitForReferencePendingList() and getAndClearReferencePendingList().
// These are separate operations to avoid a race with other threads
// that are calling waitForReferenceProcessing().
waitForReferencePendingList();
Reference<?> pendingList;
synchronized (processPendingLock) {
pendingList = getAndClearReferencePendingList();
processPendingActive = true;
}
while (pendingList != null) {
Reference<?> ref = pendingList;
pendingList = ref.discovered;
ref.discovered = null;
if (ref instanceof Cleaner) {
((Cleaner)ref).clean();
// Notify any waiters that progress has been made.
// This improves latency for nio.Bits waiters, which
// are the only important ones.
synchronized (processPendingLock) {
processPendingLock.notifyAll();
}
} else {
ref.enqueueFromPending();
}
}
// Notify any waiters of completion of current round.
synchronized (processPendingLock) {
processPendingActive = false;
processPendingLock.notifyAll();
}
}
// Wait for progress in reference processing.
//
// Returns true after waiting (for notification from the reference
// processing thread) if either (1) the VM has any pending
// references, or (2) the reference processing thread is
// processing references. Otherwise, returns false immediately.
private static boolean waitForReferenceProcessing()
throws InterruptedException
{
synchronized (processPendingLock) {
if (processPendingActive || hasReferencePendingList()) {
// Wait for progress, not necessarily completion.
processPendingLock.wait();
return true;
} else {
return false;
}
}
}
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();
// provide access in SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean waitForReferenceProcessing()
throws InterruptedException
{
return Reference.waitForReferenceProcessing();
}
@Override
public void runFinalization() {
Finalizer.runFinalization();
}
});
}
/* -- Referent accessor and setters -- */
/**
* Returns this reference object's referent. If this reference object has
* been cleared, either by the program or by the garbage collector, then
* this method returns {@code null}.
*
* @apiNote
* This method returns a strong reference to the referent. This may cause
* the garbage collector to treat it as strongly reachable until some later
* collection cycle. The {@link #refersTo(Object) refersTo} method can be
* used to avoid such strengthening when testing whether some object is
* the referent of a reference object; that is, use {@code ref.refersTo(obj)}
* rather than {@code ref.get() == obj}.
*
* @return The object to which this reference refers, or
* {@code null} if this reference object has been cleared
* @see #refersTo
*/
@IntrinsicCandidate
public T get() {
return this.referent;
}
/**
* Tests if the referent of this reference object is {@code obj}.
* Using a {@code null} {@code obj} returns {@code true} if the
* reference object has been cleared.
*
* @param obj the object to compare with this reference object's referent
* @return {@code true} if {@code obj} is the referent of this reference object
* @since 16
*/
public final boolean refersTo(T obj) {
return refersToImpl(obj);
}
/* Implementation of refersTo(), overridden for phantom references.
* This method exists only to avoid making refersTo0() virtual. Making
* refersTo0() virtual has the undesirable effect of C2 often preferring
* to call the native implementation over the intrinsic.
*/
boolean refersToImpl(T obj) {
return refersTo0(obj);
}
@IntrinsicCandidate
private native boolean refersTo0(Object o);
/**
* Clears this reference object. Invoking this method will not cause this
* object to be enqueued.
*
* <p> This method is invoked only by Java code; when the garbage collector
* clears references it does so directly, without invoking this method.
*/
public void clear() {
clear0();
}
private native void clear0();
/* -- Operations on inactive FinalReferences -- */
/* These functions are only used by FinalReference, and must only be
* called after the reference becomes inactive. While active, a
* FinalReference is considered weak but the referent is not normally
* accessed. Once a FinalReference becomes inactive it is considered a
* strong reference. These functions are used to bypass the
* corresponding weak implementations, directly accessing the referent
* field with strong semantics.
*/
/**
* Load referent with strong semantics.
*/
T getFromInactiveFinalReference() {
assert this instanceof FinalReference;
assert next != null; // I.e. FinalReference is inactive
return this.referent;
}
/**
* Clear referent with strong semantics.
*/
void clearInactiveFinalReference() {
assert this instanceof FinalReference;
assert next != null; // I.e. FinalReference is inactive
this.referent = null;
}
/* -- Queue operations -- */
/**
* Tests if this reference object is in its associated queue, if any.
* This method returns {@code true} only if all of the following conditions
* are met:
* <ul>
* <li>this reference object was registered with a queue when it was created; and
* <li>the garbage collector has added this reference object to the queue
* or {@link #enqueue()} is called; and
* <li>this reference object is not yet removed from the queue.
* </ul>
* Otherwise, this method returns {@code false}.
* This method may return {@code false} if this reference object has been cleared
* but not enqueued due to the race condition.
*
* @deprecated
* This method was originally specified to test if a reference object has
* been cleared and enqueued but was never implemented to do this test.
* This method could be misused due to the inherent race condition
* or without an associated {@code ReferenceQueue}.
* An application relying on this method to release critical resources
* could cause serious performance issue.
* An application should use {@link ReferenceQueue} to reliably determine
* what reference objects that have been enqueued or
* {@link #refersTo(Object) refersTo(null)} to determine if this reference
* object has been cleared.
*
* @return {@code true} if and only if this reference object is
* in its associated queue (if any).
*/
@Deprecated(since="16")
public boolean isEnqueued() {
return (this.queue == ReferenceQueue.ENQUEUED);
}
/**
* Clears this reference object and adds it to the queue with which
* it is registered, if any.
*
* <p> This method is invoked only by Java code; when the garbage collector
* enqueues references it does so directly, without invoking this method.
*
* @return {@code true} if this reference object was successfully
* enqueued; {@code false} if it was already enqueued or if
* it was not registered with a queue when it was created
*/
public boolean enqueue() {
clear0(); // Intentionally clear0() rather than clear()
return this.queue.enqueue(this);
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/* -- Constructors -- */
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
@ForceInline
public static void reachabilityFence(Object ref) {
}
}