1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.base.internal;
18
19 import java.lang.ref.PhantomReference;
20 import java.lang.ref.Reference;
21 import java.lang.ref.ReferenceQueue;
22 import java.lang.ref.WeakReference;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.Method;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class Finalizer implements Runnable {
50
51 private static final Logger logger
52 = Logger.getLogger(Finalizer.class.getName());
53
54
55 private static final String FINALIZABLE_REFERENCE
56 = "com.google.common.base.FinalizableReference";
57
58
59
60
61
62
63
64
65
66
67
68 public static void startFinalizer(
69 Class<?> finalizableReferenceClass,
70 ReferenceQueue<Object> queue,
71 PhantomReference<Object> frqReference) {
72
73
74
75
76
77
78
79
80 if (!finalizableReferenceClass.getName().equals(FINALIZABLE_REFERENCE)) {
81 throw new IllegalArgumentException(
82 "Expected " + FINALIZABLE_REFERENCE + ".");
83 }
84
85 Finalizer finalizer = new Finalizer(finalizableReferenceClass, queue, frqReference);
86 Thread thread = new Thread(finalizer);
87 thread.setName(Finalizer.class.getName());
88 thread.setDaemon(true);
89
90 try {
91 if (inheritableThreadLocals != null) {
92 inheritableThreadLocals.set(thread, null);
93 }
94 } catch (Throwable t) {
95 logger.log(Level.INFO, "Failed to clear thread local values inherited"
96 + " by reference finalizer thread.", t);
97 }
98
99 thread.start();
100 }
101
102 private final WeakReference<Class<?>> finalizableReferenceClassReference;
103 private final PhantomReference<Object> frqReference;
104 private final ReferenceQueue<Object> queue;
105
106 private static final Field inheritableThreadLocals
107 = getInheritableThreadLocalsField();
108
109
110 private Finalizer(
111 Class<?> finalizableReferenceClass,
112 ReferenceQueue<Object> queue,
113 PhantomReference<Object> frqReference) {
114 this.queue = queue;
115
116 this.finalizableReferenceClassReference
117 = new WeakReference<Class<?>>(finalizableReferenceClass);
118
119
120 this.frqReference = frqReference;
121 }
122
123
124
125
126 @SuppressWarnings("InfiniteLoopStatement")
127 @Override
128 public void run() {
129 while (true) {
130 try {
131 if (!cleanUp(queue.remove())) {
132 break;
133 }
134 } catch (InterruptedException e) { }
135 }
136 }
137
138
139
140
141
142
143 private boolean cleanUp(Reference<?> reference) {
144 Method finalizeReferentMethod = getFinalizeReferentMethod();
145 if (finalizeReferentMethod == null) {
146 return false;
147 }
148 do {
149
150
151
152
153 reference.clear();
154
155 if (reference == frqReference) {
156
157
158
159
160 return false;
161 }
162
163 try {
164 finalizeReferentMethod.invoke(reference);
165 } catch (Throwable t) {
166 logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
167 }
168
169
170
171
172
173 } while ((reference = queue.poll()) != null);
174 return true;
175 }
176
177
178
179
180 private Method getFinalizeReferentMethod() {
181 Class<?> finalizableReferenceClass
182 = finalizableReferenceClassReference.get();
183 if (finalizableReferenceClass == null) {
184
185
186
187
188
189
190
191
192 return null;
193 }
194 try {
195 return finalizableReferenceClass.getMethod("finalizeReferent");
196 } catch (NoSuchMethodException e) {
197 throw new AssertionError(e);
198 }
199 }
200
201 public static Field getInheritableThreadLocalsField() {
202 try {
203 Field inheritableThreadLocals
204 = Thread.class.getDeclaredField("inheritableThreadLocals");
205 inheritableThreadLocals.setAccessible(true);
206 return inheritableThreadLocals;
207 } catch (Throwable t) {
208 logger.log(Level.INFO, "Couldn't access Thread.inheritableThreadLocals."
209 + " Reference finalizer threads will inherit thread local"
210 + " values.");
211 return null;
212 }
213 }
214 }