001 /* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.base.internal; 018 019 import java.lang.ref.PhantomReference; 020 import java.lang.ref.Reference; 021 import java.lang.ref.ReferenceQueue; 022 import java.lang.ref.WeakReference; 023 import java.lang.reflect.Field; 024 import java.lang.reflect.Method; 025 import java.util.logging.Level; 026 import java.util.logging.Logger; 027 028 /** 029 * Thread that finalizes referents. All references should implement 030 * {@code com.google.common.base.FinalizableReference}. 031 * 032 * <p>While this class is public, we consider it to be *internal* and not part 033 * of our published API. It is public so we can access it reflectively across 034 * class loaders in secure environments. 035 * 036 * <p>This class can't depend on other Google Collections code. If we were 037 * to load this class in the same class loader as the rest of 038 * Google Collections, this thread would keep an indirect strong reference 039 * to the class loader and prevent it from being garbage collected. This 040 * poses a problem for environments where you want to throw away the class 041 * loader. For example, dynamically reloading a web application or unloading 042 * an OSGi bundle. 043 * 044 * <p>{@code com.google.common.base.FinalizableReferenceQueue} loads this class 045 * in its own class loader. That way, this class doesn't prevent the main 046 * class loader from getting garbage collected, and this class can detect when 047 * the main class loader has been garbage collected and stop itself. 048 * 049 * @deprecated FinalizableReferenceQueue is an unsound mechanism for cleaning up references, 050 * because (1) it's single thread can be easily overloaded, and (2) it's insistance on running 051 * a background thread is problematic in certain environments. <b>This class is scheduled for 052 * deletion in December 2012.</b> 053 */ 054 @Deprecated 055 public 056 class Finalizer extends Thread { 057 058 private static final Logger logger 059 = Logger.getLogger(Finalizer.class.getName()); 060 061 /** Name of FinalizableReference.class. */ 062 private static final String FINALIZABLE_REFERENCE 063 = "com.google.common.base.FinalizableReference"; 064 065 /** 066 * Starts the Finalizer thread. FinalizableReferenceQueue calls this method 067 * reflectively. 068 * 069 * @param finalizableReferenceClass FinalizableReference.class 070 * @param frq reference to instance of FinalizableReferenceQueue that started 071 * this thread 072 * @return ReferenceQueue which Finalizer will poll 073 */ 074 public static ReferenceQueue<Object> startFinalizer( 075 Class<?> finalizableReferenceClass, Object frq) { 076 /* 077 * We use FinalizableReference.class for two things: 078 * 079 * 1) To invoke FinalizableReference.finalizeReferent() 080 * 081 * 2) To detect when FinalizableReference's class loader has to be garbage 082 * collected, at which point, Finalizer can stop running 083 */ 084 if (!finalizableReferenceClass.getName().equals(FINALIZABLE_REFERENCE)) { 085 throw new IllegalArgumentException( 086 "Expected " + FINALIZABLE_REFERENCE + "."); 087 } 088 089 Finalizer finalizer = new Finalizer(finalizableReferenceClass, frq); 090 finalizer.start(); 091 return finalizer.queue; 092 } 093 094 private final WeakReference<Class<?>> finalizableReferenceClassReference; 095 private final PhantomReference<Object> frqReference; 096 private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 097 098 private static final Field inheritableThreadLocals 099 = getInheritableThreadLocalsField(); 100 101 /** Constructs a new finalizer thread. */ 102 private Finalizer(Class<?> finalizableReferenceClass, Object frq) { 103 super(Finalizer.class.getName()); 104 105 this.finalizableReferenceClassReference 106 = new WeakReference<Class<?>>(finalizableReferenceClass); 107 108 // Keep track of the FRQ that started us so we know when to stop. 109 this.frqReference = new PhantomReference<Object>(frq, queue); 110 111 setDaemon(true); 112 113 try { 114 if (inheritableThreadLocals != null) { 115 inheritableThreadLocals.set(this, null); 116 } 117 } catch (Throwable t) { 118 logger.log(Level.INFO, "Failed to clear thread local values inherited" 119 + " by reference finalizer thread.", t); 120 } 121 122 // TODO(fry): Priority? 123 } 124 125 /** 126 * Loops continuously, pulling references off the queue and cleaning them up. 127 */ 128 @SuppressWarnings("InfiniteLoopStatement") 129 @Override 130 public void run() { 131 try { 132 while (true) { 133 try { 134 cleanUp(queue.remove()); 135 } catch (InterruptedException e) { /* ignore */ } 136 } 137 } catch (ShutDown shutDown) { /* ignore */ } 138 } 139 140 /** 141 * Cleans up a single reference. Catches and logs all throwables. 142 */ 143 private void cleanUp(Reference<?> reference) throws ShutDown { 144 Method finalizeReferentMethod = getFinalizeReferentMethod(); 145 do { 146 /* 147 * This is for the benefit of phantom references. Weak and soft 148 * references will have already been cleared by this point. 149 */ 150 reference.clear(); 151 152 if (reference == frqReference) { 153 /* 154 * The client no longer has a reference to the 155 * FinalizableReferenceQueue. We can stop. 156 */ 157 throw new ShutDown(); 158 } 159 160 try { 161 finalizeReferentMethod.invoke(reference); 162 } catch (Throwable t) { 163 logger.log(Level.SEVERE, "Error cleaning up after reference.", t); 164 } 165 166 /* 167 * Loop as long as we have references available so as not to waste 168 * CPU looking up the Method over and over again. 169 */ 170 } while ((reference = queue.poll()) != null); 171 } 172 173 /** 174 * Looks up FinalizableReference.finalizeReferent() method. 175 */ 176 private Method getFinalizeReferentMethod() throws ShutDown { 177 Class<?> finalizableReferenceClass 178 = finalizableReferenceClassReference.get(); 179 if (finalizableReferenceClass == null) { 180 /* 181 * FinalizableReference's class loader was reclaimed. While there's a 182 * chance that other finalizable references could be enqueued 183 * subsequently (at which point the class loader would be resurrected 184 * by virtue of us having a strong reference to it), we should pretty 185 * much just shut down and make sure we don't keep it alive any longer 186 * than necessary. 187 */ 188 throw new ShutDown(); 189 } 190 try { 191 return finalizableReferenceClass.getMethod("finalizeReferent"); 192 } catch (NoSuchMethodException e) { 193 throw new AssertionError(e); 194 } 195 } 196 197 public static Field getInheritableThreadLocalsField() { 198 try { 199 Field inheritableThreadLocals 200 = Thread.class.getDeclaredField("inheritableThreadLocals"); 201 inheritableThreadLocals.setAccessible(true); 202 return inheritableThreadLocals; 203 } catch (Throwable t) { 204 logger.log(Level.INFO, "Couldn't access Thread.inheritableThreadLocals." 205 + " Reference finalizer threads will inherit thread local" 206 + " values."); 207 return null; 208 } 209 } 210 211 /** Indicates that it's time to shut down the Finalizer. */ 212 @SuppressWarnings("serial") // Never serialized or thrown out of this class. 213 private static class ShutDown extends Exception { } 214 }