1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.executor;
21
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.LinkedBlockingQueue;
28 import java.util.concurrent.RejectedExecutionHandler;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.ThreadPoolExecutor;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.atomic.AtomicInteger;
33
34 import org.apache.mina.core.session.IoEvent;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class UnorderedThreadPoolExecutor extends ThreadPoolExecutor {
56
57 private static final Runnable EXIT_SIGNAL = new Runnable() {
58 public void run() {
59 throw new Error(
60 "This method shouldn't be called. " +
61 "Please file a bug report.");
62 }
63 };
64
65 private final Set<Worker> workers = new HashSet<Worker>();
66
67 private volatile int corePoolSize;
68 private volatile int maximumPoolSize;
69 private volatile int largestPoolSize;
70 private final AtomicInteger idleWorkers = new AtomicInteger();
71
72 private long completedTaskCount;
73 private volatile boolean shutdown;
74
75 private final IoEventQueueHandler queueHandler;
76
77 public UnorderedThreadPoolExecutor() {
78 this(16);
79 }
80
81 public UnorderedThreadPoolExecutor(int maximumPoolSize) {
82 this(0, maximumPoolSize);
83 }
84
85 public UnorderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize) {
86 this(corePoolSize, maximumPoolSize, 30, TimeUnit.SECONDS);
87 }
88
89 public UnorderedThreadPoolExecutor(
90 int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
91 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory());
92 }
93
94 public UnorderedThreadPoolExecutor(
95 int corePoolSize, int maximumPoolSize,
96 long keepAliveTime, TimeUnit unit,
97 IoEventQueueHandler queueHandler) {
98 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory(), queueHandler);
99 }
100
101 public UnorderedThreadPoolExecutor(
102 int corePoolSize, int maximumPoolSize,
103 long keepAliveTime, TimeUnit unit,
104 ThreadFactory threadFactory) {
105 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, threadFactory, null);
106 }
107
108 public UnorderedThreadPoolExecutor(
109 int corePoolSize, int maximumPoolSize,
110 long keepAliveTime, TimeUnit unit,
111 ThreadFactory threadFactory, IoEventQueueHandler queueHandler) {
112 super(0, 1, keepAliveTime, unit, new LinkedBlockingQueue<Runnable>(), threadFactory, new AbortPolicy());
113 if (corePoolSize < 0) {
114 throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
115 }
116
117 if (maximumPoolSize == 0 || maximumPoolSize < corePoolSize) {
118 throw new IllegalArgumentException("maximumPoolSize: " + maximumPoolSize);
119 }
120
121 if (queueHandler == null) {
122 queueHandler = IoEventQueueHandler.NOOP;
123 }
124
125 this.corePoolSize = corePoolSize;
126 this.maximumPoolSize = maximumPoolSize;
127 this.queueHandler = queueHandler;
128 }
129
130 public IoEventQueueHandler getQueueHandler() {
131 return queueHandler;
132 }
133
134 @Override
135 public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
136
137 }
138
139 private void addWorker() {
140 synchronized (workers) {
141 if (workers.size() >= maximumPoolSize) {
142 return;
143 }
144
145 Worker worker = new Worker();
146 Thread thread = getThreadFactory().newThread(worker);
147 idleWorkers.incrementAndGet();
148 thread.start();
149 workers.add(worker);
150
151 if (workers.size() > largestPoolSize) {
152 largestPoolSize = workers.size();
153 }
154 }
155 }
156
157 private void addWorkerIfNecessary() {
158 if (idleWorkers.get() == 0) {
159 synchronized (workers) {
160 if (workers.isEmpty() || idleWorkers.get() == 0) {
161 addWorker();
162 }
163 }
164 }
165 }
166
167 private void removeWorker() {
168 synchronized (workers) {
169 if (workers.size() <= corePoolSize) {
170 return;
171 }
172 getQueue().offer(EXIT_SIGNAL);
173 }
174 }
175
176 @Override
177 public int getMaximumPoolSize() {
178 return maximumPoolSize;
179 }
180
181 @Override
182 public void setMaximumPoolSize(int maximumPoolSize) {
183 if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) {
184 throw new IllegalArgumentException("maximumPoolSize: "
185 + maximumPoolSize);
186 }
187
188 synchronized (workers) {
189 this.maximumPoolSize = maximumPoolSize;
190 int difference = workers.size() - maximumPoolSize;
191 while (difference > 0) {
192 removeWorker();
193 --difference;
194 }
195 }
196 }
197
198 @Override
199 public boolean awaitTermination(long timeout, TimeUnit unit)
200 throws InterruptedException {
201
202 long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
203
204 synchronized (workers) {
205 while (!isTerminated()) {
206 long waitTime = deadline - System.currentTimeMillis();
207 if (waitTime <= 0) {
208 break;
209 }
210
211 workers.wait(waitTime);
212 }
213 }
214 return isTerminated();
215 }
216
217 @Override
218 public boolean isShutdown() {
219 return shutdown;
220 }
221
222 @Override
223 public boolean isTerminated() {
224 if (!shutdown) {
225 return false;
226 }
227
228 synchronized (workers) {
229 return workers.isEmpty();
230 }
231 }
232
233 @Override
234 public void shutdown() {
235 if (shutdown) {
236 return;
237 }
238
239 shutdown = true;
240
241 synchronized (workers) {
242 for (int i = workers.size(); i > 0; i --) {
243 getQueue().offer(EXIT_SIGNAL);
244 }
245 }
246 }
247
248 @Override
249 public List<Runnable> shutdownNow() {
250 shutdown();
251
252 List<Runnable> answer = new ArrayList<Runnable>();
253 Runnable task;
254 while ((task = getQueue().poll()) != null) {
255 if (task == EXIT_SIGNAL) {
256 getQueue().offer(EXIT_SIGNAL);
257 Thread.yield();
258 continue;
259 }
260
261 getQueueHandler().polled(this, (IoEvent) task);
262 answer.add(task);
263 }
264
265 return answer;
266 }
267
268 @Override
269 public void execute(Runnable task) {
270 if (shutdown) {
271 rejectTask(task);
272 }
273
274 checkTaskType(task);
275
276 IoEvent e = (IoEvent) task;
277 boolean offeredEvent = queueHandler.accept(this, e);
278 if (offeredEvent) {
279 getQueue().offer(e);
280 }
281
282 addWorkerIfNecessary();
283
284 if (offeredEvent) {
285 queueHandler.offered(this, e);
286 }
287 }
288
289 private void rejectTask(Runnable task) {
290 getRejectedExecutionHandler().rejectedExecution(task, this);
291 }
292
293 private void checkTaskType(Runnable task) {
294 if (!(task instanceof IoEvent)) {
295 throw new IllegalArgumentException("task must be an IoEvent or its subclass.");
296 }
297 }
298
299 @Override
300 public int getActiveCount() {
301 synchronized (workers) {
302 return workers.size() - idleWorkers.get();
303 }
304 }
305
306 @Override
307 public long getCompletedTaskCount() {
308 synchronized (workers) {
309 long answer = completedTaskCount;
310 for (Worker w: workers) {
311 answer += w.completedTaskCount;
312 }
313
314 return answer;
315 }
316 }
317
318 @Override
319 public int getLargestPoolSize() {
320 return largestPoolSize;
321 }
322
323 @Override
324 public int getPoolSize() {
325 synchronized (workers) {
326 return workers.size();
327 }
328 }
329
330 @Override
331 public long getTaskCount() {
332 return getCompletedTaskCount();
333 }
334
335 @Override
336 public boolean isTerminating() {
337 synchronized (workers) {
338 return isShutdown() && !isTerminated();
339 }
340 }
341
342 @Override
343 public int prestartAllCoreThreads() {
344 int answer = 0;
345 synchronized (workers) {
346 for (int i = corePoolSize - workers.size() ; i > 0; i --) {
347 addWorker();
348 answer ++;
349 }
350 }
351 return answer;
352 }
353
354 @Override
355 public boolean prestartCoreThread() {
356 synchronized (workers) {
357 if (workers.size() < corePoolSize) {
358 addWorker();
359 return true;
360 } else {
361 return false;
362 }
363 }
364 }
365
366 @Override
367 public void purge() {
368
369 }
370
371 @Override
372 public boolean remove(Runnable task) {
373 boolean removed = super.remove(task);
374 if (removed) {
375 getQueueHandler().polled(this, (IoEvent) task);
376 }
377 return removed;
378 }
379
380 @Override
381 public int getCorePoolSize() {
382 return corePoolSize;
383 }
384
385 @Override
386 public void setCorePoolSize(int corePoolSize) {
387 if (corePoolSize < 0) {
388 throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
389 }
390 if (corePoolSize > maximumPoolSize) {
391 throw new IllegalArgumentException("corePoolSize exceeds maximumPoolSize");
392 }
393
394 synchronized (workers) {
395 if (this.corePoolSize > corePoolSize) {
396 for (int i = this.corePoolSize - corePoolSize; i > 0; i --) {
397 removeWorker();
398 }
399 }
400 this.corePoolSize = corePoolSize;
401 }
402 }
403
404 private class Worker implements Runnable {
405
406 private volatile long completedTaskCount;
407 private Thread thread;
408
409 public void run() {
410 thread = Thread.currentThread();
411
412 try {
413 for (;;) {
414 Runnable task = fetchTask();
415
416 idleWorkers.decrementAndGet();
417
418 if (task == null) {
419 synchronized (workers) {
420 if (workers.size() > corePoolSize) {
421
422 workers.remove(this);
423 break;
424 }
425 }
426 }
427
428 if (task == EXIT_SIGNAL) {
429 break;
430 }
431
432 try {
433 if (task != null) {
434 queueHandler.polled(UnorderedThreadPoolExecutor.this, (IoEvent) task);
435 runTask(task);
436 }
437 } finally {
438 idleWorkers.incrementAndGet();
439 }
440 }
441 } finally {
442 synchronized (workers) {
443 workers.remove(this);
444 UnorderedThreadPoolExecutor.this.completedTaskCount += completedTaskCount;
445 workers.notifyAll();
446 }
447 }
448 }
449
450 private Runnable fetchTask() {
451 Runnable task = null;
452 long currentTime = System.currentTimeMillis();
453 long deadline = currentTime + getKeepAliveTime(TimeUnit.MILLISECONDS);
454 for (;;) {
455 try {
456 long waitTime = deadline - currentTime;
457 if (waitTime <= 0) {
458 break;
459 }
460
461 try {
462 task = getQueue().poll(waitTime, TimeUnit.MILLISECONDS);
463 break;
464 } finally {
465 if (task == null) {
466 currentTime = System.currentTimeMillis();
467 }
468 }
469 } catch (InterruptedException e) {
470
471 continue;
472 }
473 }
474 return task;
475 }
476
477 private void runTask(Runnable task) {
478 beforeExecute(thread, task);
479 boolean ran = false;
480 try {
481 task.run();
482 ran = true;
483 afterExecute(task, null);
484 completedTaskCount ++;
485 } catch (RuntimeException e) {
486 if (!ran) {
487 afterExecute(task, e);
488 }
489 throw e;
490 }
491 }
492 }
493 }