59 final ReferenceQueue<Object> queue;
60
61 /**
62 * Called by Cleaner static initialization to provide the function
63 * to map from Cleaner to CleanerImpl.
64 * @param access a function to map from Cleaner to CleanerImpl
65 */
66 public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
67 if (cleanerImplAccess == null) {
68 cleanerImplAccess = access;
69 } else {
70 throw new InternalError("cleanerImplAccess");
71 }
72 }
73
74 /**
75 * Called to get the CleanerImpl for a Cleaner.
76 * @param cleaner the cleaner
77 * @return the corresponding CleanerImpl
78 */
79 static CleanerImpl getCleanerImpl(Cleaner cleaner) {
80 return cleanerImplAccess.apply(cleaner);
81 }
82
83 /**
84 * Constructor for CleanerImpl.
85 */
86 public CleanerImpl() {
87 queue = new ReferenceQueue<>();
88 phantomCleanableList = new PhantomCleanableRef();
89 weakCleanableList = new WeakCleanableRef();
90 softCleanableList = new SoftCleanableRef();
91 }
92
93 /**
94 * Starts the Cleaner implementation.
95 * Ensure this is the CleanerImpl for the Cleaner.
96 * When started waits for Cleanables to be queued.
97 * @param cleaner the cleaner
98 * @param threadFactory the thread factory
99 */
130 */
131 private void run() {
132 Thread t = Thread.currentThread();
133 InnocuousThread mlThread = (t instanceof InnocuousThread)
134 ? (InnocuousThread) t
135 : null;
136 while (!phantomCleanableList.isListEmpty() ||
137 !weakCleanableList.isListEmpty() ||
138 !softCleanableList.isListEmpty()) {
139 if (mlThread != null) {
140 // Clear the thread locals
141 mlThread.eraseThreadLocals();
142 }
143 try {
144 // Wait for a Ref, with a timeout to avoid getting hung
145 // due to a race with clear/clean
146 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
147 if (ref != null) {
148 ref.clean();
149 }
150 } catch (InterruptedException i) {
151 continue; // ignore the interruption
152 } catch (Throwable e) {
153 // ignore exceptions from the cleanup action
154 }
155 }
156 }
157
158 /**
159 * Perform cleaning on an unreachable PhantomReference.
160 */
161 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
162 private final Runnable action;
163
164 /**
165 * Constructor for a phantom cleanable reference.
166 * @param obj the object to monitor
167 * @param cleaner the cleaner
168 * @param action the action Runnable
169 */
170 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
171 super(obj, cleaner);
172 this.action = action;
173 }
174
175 /**
|
59 final ReferenceQueue<Object> queue;
60
61 /**
62 * Called by Cleaner static initialization to provide the function
63 * to map from Cleaner to CleanerImpl.
64 * @param access a function to map from Cleaner to CleanerImpl
65 */
66 public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
67 if (cleanerImplAccess == null) {
68 cleanerImplAccess = access;
69 } else {
70 throw new InternalError("cleanerImplAccess");
71 }
72 }
73
74 /**
75 * Called to get the CleanerImpl for a Cleaner.
76 * @param cleaner the cleaner
77 * @return the corresponding CleanerImpl
78 */
79 public static CleanerImpl getCleanerImpl(Cleaner cleaner) {
80 return cleanerImplAccess.apply(cleaner);
81 }
82
83 /**
84 * Constructor for CleanerImpl.
85 */
86 public CleanerImpl() {
87 queue = new ReferenceQueue<>();
88 phantomCleanableList = new PhantomCleanableRef();
89 weakCleanableList = new WeakCleanableRef();
90 softCleanableList = new SoftCleanableRef();
91 }
92
93 /**
94 * Starts the Cleaner implementation.
95 * Ensure this is the CleanerImpl for the Cleaner.
96 * When started waits for Cleanables to be queued.
97 * @param cleaner the cleaner
98 * @param threadFactory the thread factory
99 */
130 */
131 private void run() {
132 Thread t = Thread.currentThread();
133 InnocuousThread mlThread = (t instanceof InnocuousThread)
134 ? (InnocuousThread) t
135 : null;
136 while (!phantomCleanableList.isListEmpty() ||
137 !weakCleanableList.isListEmpty() ||
138 !softCleanableList.isListEmpty()) {
139 if (mlThread != null) {
140 // Clear the thread locals
141 mlThread.eraseThreadLocals();
142 }
143 try {
144 // Wait for a Ref, with a timeout to avoid getting hung
145 // due to a race with clear/clean
146 Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
147 if (ref != null) {
148 ref.clean();
149 }
150 } catch (Throwable e) {
151 // ignore exceptions from the cleanup action
152 // (including interruption of cleanup thread)
153 }
154 }
155 }
156
157 /**
158 * Processes all Cleanable(s) that have been waiting in the queue.
159 *
160 * @return {@code true} if any Cleanable was found in the queue and
161 * was processed or {@code false} if the queue was empty.
162 */
163 public boolean drainQueue() {
164 boolean cleaned = false;
165 Cleanable ref;
166 while ((ref = (Cleanable) queue.poll()) != null) {
167 try {
168 ref.clean();
169 } catch (Throwable t) {
170 // ignore exceptions from the cleanup action
171 }
172 cleaned = true;
173 }
174 return cleaned;
175 }
176
177 /**
178 * Perform cleaning on an unreachable PhantomReference.
179 */
180 public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
181 private final Runnable action;
182
183 /**
184 * Constructor for a phantom cleanable reference.
185 * @param obj the object to monitor
186 * @param cleaner the cleaner
187 * @param action the action Runnable
188 */
189 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
190 super(obj, cleaner);
191 this.action = action;
192 }
193
194 /**
|