All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.lang.ref.FinalizerReference Maven / Gradle / Ivy

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package java.lang.ref;

/**
 * @hide
 */
public final class FinalizerReference extends Reference {
    // This queue contains those objects eligible for finalization.
    public static final ReferenceQueue queue = new ReferenceQueue();

    // Guards the list (not the queue).
    private static final Object LIST_LOCK = new Object();

    // This list contains a FinalizerReference for every finalizable object in the heap.
    // Objects in this list may or may not be eligible for finalization yet.
    private static FinalizerReference head = null;

    // The links used to construct the list.
    private FinalizerReference prev;
    private FinalizerReference next;

    // When the GC wants something finalized, it moves it from the 'referent' field to
    // the 'zombie' field instead.
    private T zombie;

    public FinalizerReference(T r, ReferenceQueue q) {
        super(r, q);
    }

    @Override public T get() {
        return zombie;
    }

    @Override public void clear() {
        zombie = null;
    }

    public static void add(Object referent) {
        FinalizerReference reference = new FinalizerReference(referent, queue);
        synchronized (LIST_LOCK) {
            reference.prev = null;
            reference.next = head;
            if (head != null) {
                head.prev = reference;
            }
            head = reference;
        }
    }

    public static void remove(FinalizerReference reference) {
        synchronized (LIST_LOCK) {
            FinalizerReference next = reference.next;
            FinalizerReference prev = reference.prev;
            reference.next = null;
            reference.prev = null;
            if (prev != null) {
                prev.next = next;
            } else {
                head = next;
            }
            if (next != null) {
                next.prev = prev;
            }
        }
    }

    /**
     * Waits for all currently-enqueued references to be finalized.
     */
    public static void finalizeAllEnqueued() throws InterruptedException {
        Sentinel sentinel = new Sentinel();
        enqueueSentinelReference(sentinel);
        sentinel.awaitFinalization();
    }

    private static void enqueueSentinelReference(Sentinel sentinel) {
        synchronized (LIST_LOCK) {
            // When a finalizable object is allocated, a FinalizerReference is added to the list.
            // We search the list for that FinalizerReference (it should be at or near the head),
            // and then put it on the queue so that it can be finalized.
            for (FinalizerReference r = head; r != null; r = r.next) {
                if (r.referent == sentinel) {
                    FinalizerReference sentinelReference = (FinalizerReference) r;
                    sentinelReference.referent = null;
                    sentinelReference.zombie = sentinel;
                    sentinelReference.enqueueInternal();
                    return;
                }
            }
        }
        // We just created a finalizable object and still hold a reference to it.
        // It must be on the list.
        throw new AssertionError("newly-created live Sentinel not on list!");
    }

    /**
     * A marker object that we can immediately enqueue. When this object's
     * finalize() method is called, we know all previously-enqueued finalizable
     * references have been finalized.
     */
    private static class Sentinel {
        boolean finalized = false;

        @Override protected synchronized void finalize() throws Throwable {
            if (finalized) {
                throw new AssertionError();
            }
            finalized = true;
            notifyAll();
        }

        synchronized void awaitFinalization() throws InterruptedException {
            while (!finalized) {
                wait();
            }
        }
    }
}