jdk/src/share/classes/java/lang/ref/Finalizer.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/ref/Finalizer.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,197 @@
+/*
+ * Copyright 1997-2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.lang.ref;
+
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+
+
+final class Finalizer extends FinalReference { /* Package-private; must be in
+                                                  same package as the Reference
+                                                  class */
+
+    /* A native method that invokes an arbitrary object's finalize method is
+       required since the finalize method is protected
+     */
+    static native void invokeFinalizeMethod(Object o) throws Throwable;
+
+    static private ReferenceQueue queue = new ReferenceQueue();
+    static private Finalizer unfinalized = null;
+    static private Object lock = new Object();
+
+    private Finalizer
+        next = null,
+        prev = null;
+
+    private boolean hasBeenFinalized() {
+        return (next == this);
+    }
+
+    private void add() {
+        synchronized (lock) {
+            if (unfinalized != null) {
+                this.next = unfinalized;
+                unfinalized.prev = this;
+            }
+            unfinalized = this;
+        }
+    }
+
+    private void remove() {
+        synchronized (lock) {
+            if (unfinalized == this) {
+                if (this.next != null) {
+                    unfinalized = this.next;
+                } else {
+                    unfinalized = this.prev;
+                }
+            }
+            if (this.next != null) {
+                this.next.prev = this.prev;
+            }
+            if (this.prev != null) {
+                this.prev.next = this.next;
+            }
+            this.next = this;   /* Indicates that this has been finalized */
+            this.prev = this;
+        }
+    }
+
+    private Finalizer(Object finalizee) {
+        super(finalizee, queue);
+        add();
+    }
+
+    /* Invoked by VM */
+    static void register(Object finalizee) {
+        new Finalizer(finalizee);
+    }
+
+    private void runFinalizer() {
+        synchronized (this) {
+            if (hasBeenFinalized()) return;
+            remove();
+        }
+        try {
+            Object finalizee = this.get();
+            if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
+                invokeFinalizeMethod(finalizee);
+                /* Clear stack slot containing this variable, to decrease
+                   the chances of false retention with a conservative GC */
+                finalizee = null;
+            }
+        } catch (Throwable x) { }
+        super.clear();
+    }
+
+    /* Create a privileged secondary finalizer thread in the system thread
+       group for the given Runnable, and wait for it to complete.
+
+       This method is used by both runFinalization and runFinalizersOnExit.
+       The former method invokes all pending finalizers, while the latter
+       invokes all uninvoked finalizers if on-exit finalization has been
+       enabled.
+
+       These two methods could have been implemented by offloading their work
+       to the regular finalizer thread and waiting for that thread to finish.
+       The advantage of creating a fresh thread, however, is that it insulates
+       invokers of these methods from a stalled or deadlocked finalizer thread.
+     */
+    private static void forkSecondaryFinalizer(final Runnable proc) {
+        PrivilegedAction pa = new PrivilegedAction() {
+            public Object run() {
+                ThreadGroup tg = Thread.currentThread().getThreadGroup();
+                for (ThreadGroup tgn = tg;
+                     tgn != null;
+                     tg = tgn, tgn = tg.getParent());
+                Thread sft = new Thread(tg, proc, "Secondary finalizer");
+                sft.start();
+                try {
+                    sft.join();
+                } catch (InterruptedException x) {
+                    /* Ignore */
+                }
+                return null;
+            }};
+        AccessController.doPrivileged(pa);
+    }
+
+    /* Called by Runtime.runFinalization() */
+    static void runFinalization() {
+        forkSecondaryFinalizer(new Runnable() {
+            public void run() {
+                for (;;) {
+                    Finalizer f = (Finalizer)queue.poll();
+                    if (f == null) break;
+                    f.runFinalizer();
+                }
+            }
+        });
+    }
+
+    /* Invoked by java.lang.Shutdown */
+    static void runAllFinalizers() {
+        forkSecondaryFinalizer(new Runnable() {
+            public void run() {
+                for (;;) {
+                    Finalizer f;
+                    synchronized (lock) {
+                        f = unfinalized;
+                        if (f == null) break;
+                        unfinalized = f.next;
+                    }
+                    f.runFinalizer();
+                }}});
+    }
+
+    private static class FinalizerThread extends Thread {
+        FinalizerThread(ThreadGroup g) {
+            super(g, "Finalizer");
+        }
+        public void run() {
+            for (;;) {
+                try {
+                    Finalizer f = (Finalizer)queue.remove();
+                    f.runFinalizer();
+                } catch (InterruptedException x) {
+                    continue;
+                }
+            }
+        }
+    }
+
+    static {
+        ThreadGroup tg = Thread.currentThread().getThreadGroup();
+        for (ThreadGroup tgn = tg;
+             tgn != null;
+             tg = tgn, tgn = tg.getParent());
+        Thread finalizer = new FinalizerThread(tg);
+        finalizer.setPriority(Thread.MAX_PRIORITY - 2);
+        finalizer.setDaemon(true);
+        finalizer.start();
+    }
+
+}