1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.pool2.impl;
18
19 import java.lang.ref.WeakReference;
20 import java.security.AccessController;
21 import java.security.PrivilegedAction;
22 import java.time.Duration;
23 import java.util.HashMap;
24 import java.util.Map.Entry;
25 import java.util.concurrent.ScheduledFuture;
26 import java.util.concurrent.ScheduledThreadPoolExecutor;
27 import java.util.concurrent.ThreadFactory;
28 import java.util.concurrent.TimeUnit;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 class EvictionTimer {
50
51
52
53
54 private static class EvictorThreadFactory implements ThreadFactory {
55
56 @Override
57 public Thread newThread(final Runnable runnable) {
58 final Thread thread = new Thread(null, runnable, "commons-pool-evictor");
59 thread.setDaemon(true);
60 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
61 thread.setContextClassLoader(EvictorThreadFactory.class.getClassLoader());
62 return null;
63 });
64
65 return thread;
66 }
67 }
68
69
70
71
72
73 private static class Reaper implements Runnable {
74 @Override
75 public void run() {
76 synchronized (EvictionTimer.class) {
77 for (final Entry<WeakReference<BaseGenericObjectPool<?>.Evictor>, WeakRunner<BaseGenericObjectPool<?>.Evictor>> entry : TASK_MAP
78 .entrySet()) {
79 if (entry.getKey().get() == null) {
80 executor.remove(entry.getValue());
81 TASK_MAP.remove(entry.getKey());
82 }
83 }
84 if (TASK_MAP.isEmpty() && executor != null) {
85 executor.shutdown();
86 executor.setCorePoolSize(0);
87 executor = null;
88 }
89 }
90 }
91 }
92
93
94
95
96
97
98 private static class WeakRunner<R extends Runnable> implements Runnable {
99
100 private final WeakReference<R> ref;
101
102
103
104
105
106
107 private WeakRunner(final WeakReference<R> ref) {
108 this.ref = ref;
109 }
110
111 @Override
112 public void run() {
113 final Runnable task = ref.get();
114 if (task != null) {
115 task.run();
116 } else {
117 executor.remove(this);
118 TASK_MAP.remove(ref);
119 }
120 }
121 }
122
123
124
125 private static ScheduledThreadPoolExecutor executor;
126
127
128 private static final HashMap<
129 WeakReference<BaseGenericObjectPool<?>.Evictor>,
130 WeakRunner<BaseGenericObjectPool<?>.Evictor>> TASK_MAP = new HashMap<>();
131
132
133
134
135
136
137
138
139
140
141 static synchronized void cancel(final BaseGenericObjectPool<?>.Evictor evictor, final Duration timeout,
142 final boolean restarting) {
143 if (evictor != null) {
144 evictor.cancel();
145 remove(evictor);
146 }
147 if (!restarting && executor != null && TASK_MAP.isEmpty()) {
148 executor.shutdown();
149 try {
150 executor.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS);
151 } catch (final InterruptedException e) {
152
153
154 }
155 executor.setCorePoolSize(0);
156 executor = null;
157 }
158 }
159
160
161
162
163
164
165 static ScheduledThreadPoolExecutor getExecutor() {
166 return executor;
167 }
168
169
170
171
172 static synchronized int getNumTasks() {
173 return TASK_MAP.size();
174 }
175
176
177
178
179
180
181 static HashMap<WeakReference<BaseGenericObjectPool<?>.Evictor>, WeakRunner<BaseGenericObjectPool<?>.Evictor>> getTaskMap() {
182 return TASK_MAP;
183 }
184
185
186
187
188
189
190
191 private static void remove(final BaseGenericObjectPool<?>.Evictor evictor) {
192 for (final Entry<WeakReference<BaseGenericObjectPool<?>.Evictor>, WeakRunner<BaseGenericObjectPool<?>.Evictor>> entry : TASK_MAP.entrySet()) {
193 if (entry.getKey().get() == evictor) {
194 executor.remove(entry.getValue());
195 TASK_MAP.remove(entry.getKey());
196 break;
197 }
198 }
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212 static synchronized void schedule(
213 final BaseGenericObjectPool<?>.Evictor task, final Duration delay, final Duration period) {
214 if (null == executor) {
215 executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
216 executor.setRemoveOnCancelPolicy(true);
217 executor.scheduleAtFixedRate(new Reaper(), delay.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS);
218 }
219 final WeakReference<BaseGenericObjectPool<?>.Evictor> ref = new WeakReference<>(task);
220 final WeakRunner<BaseGenericObjectPool<?>.Evictor> runner = new WeakRunner<>(ref);
221 final ScheduledFuture<?> scheduledFuture = executor.scheduleWithFixedDelay(runner, delay.toMillis(),
222 period.toMillis(), TimeUnit.MILLISECONDS);
223 task.setScheduledFuture(scheduledFuture);
224 TASK_MAP.put(ref, runner);
225 }
226
227
228 private EvictionTimer() {
229
230 }
231
232
233
234
235 @Override
236 public String toString() {
237 final StringBuilder builder = new StringBuilder();
238 builder.append("EvictionTimer []");
239 return builder.toString();
240 }
241
242 }